Coverage Report

Created: 2026-01-13 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/server.c
Line
Count
Source
1
/*
2
 * server.c - functions for creating a SSH server
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2004-2013 by Aris Adamantiadis
7
 *
8
 * The SSH Library is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or (at your
11
 * option) any later version.
12
 *
13
 * The SSH Library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16
 * License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with the SSH Library; see the file COPYING.  If not, write to
20
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21
 * MA 02111-1307, USA.
22
 */
23
24
#include "config.h"
25
26
#include <errno.h>
27
#include <fcntl.h>
28
#include <stdio.h>
29
#include <string.h>
30
#include <stdlib.h>
31
32
#ifdef _WIN32
33
# include <winsock2.h>
34
# include <ws2tcpip.h>
35
36
  /*
37
   * <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
38
   * available on some platforms like MinGW.
39
   */
40
# ifdef HAVE_WSPIAPI_H
41
#  include <wspiapi.h>
42
# endif
43
#else
44
# include <netinet/in.h>
45
#endif
46
47
#include "libssh/buffer.h"
48
#include "libssh/curve25519.h"
49
#include "libssh/dh.h"
50
#include "libssh/gssapi.h"
51
#include "libssh/kex.h"
52
#include "libssh/libssh.h"
53
#include "libssh/messages.h"
54
#include "libssh/misc.h"
55
#include "libssh/options.h"
56
#include "libssh/packet.h"
57
#include "libssh/pki.h"
58
#include "libssh/priv.h"
59
#include "libssh/server.h"
60
#include "libssh/session.h"
61
#include "libssh/socket.h"
62
#include "libssh/ssh2.h"
63
#include "libssh/token.h"
64
65
29.6k
#define set_status(session, status) do {\
66
29.6k
        if (session->common.callbacks && session->common.callbacks->connect_status_function) \
67
29.6k
            session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
68
29.6k
    } while (0)
69
70
/**
71
 * @addtogroup libssh_server
72
 *
73
 * @{
74
 */
75
76
/**
77
 * @internal
78
 * @brief Sets the server's key exchange, encryption, MAC, and compression
79
 * algorithms.
80
 *
81
 * Prepares the server key exchange (KEX) proposals by prioritizing the
82
 * available host keys (Ed25519, ECDSA, RSA)  based on their strength and fills
83
 * in the KEX method lists based on session options or defaults. This is
84
 * essential for negotiating secure communication parameters in the SSH
85
 * handshake.
86
 *
87
 * @param[in] session The SSH session to set up.
88
 *
89
 * @return `SSH_OK` on success, `SSH_ERROR` on failure (e.g., no host keys
90
 * available, random number generation error, or memory allocation failure).
91
 */
92
int server_set_kex(ssh_session session)
93
12.7k
{
94
12.7k
    struct ssh_kex_struct *server = &session->next_crypto->server_kex;
95
12.7k
    int i, j, rc;
96
12.7k
    const char *wanted = NULL, *allowed = NULL;
97
12.7k
    char *kept = NULL;
98
12.7k
    char hostkeys[128] = {0};
99
12.7k
    enum ssh_keytypes_e keytype;
100
12.7k
    size_t len;
101
12.7k
    int ok;
102
#ifdef WITH_GSSAPI
103
    char *gssapi_algs = NULL;
104
#endif /* WITH_GSSAPI */
105
106
    /* Skip if already set, for example for the rekey or when we do the guessing
107
     * it could have been already used to make some protocol decisions. */
108
12.7k
    if (server->methods[0] != NULL) {
109
6.04k
        return SSH_OK;
110
6.04k
    }
111
112
6.66k
    ok = ssh_get_random(server->cookie, 16, 0);
113
6.66k
    if (!ok) {
114
0
        ssh_set_error(session, SSH_FATAL, "PRNG error");
115
0
        return -1;
116
0
    }
117
118
6.66k
    if (session->srv.ed25519_key != NULL) {
119
0
        snprintf(hostkeys,
120
0
                 sizeof(hostkeys),
121
0
                 "%s",
122
0
                 ssh_key_type_to_char(ssh_key_type(session->srv.ed25519_key)));
123
0
    }
124
6.66k
#ifdef HAVE_ECC
125
6.66k
    if (session->srv.ecdsa_key != NULL) {
126
0
        len = strlen(hostkeys);
127
0
        snprintf(hostkeys + len, sizeof(hostkeys) - len,
128
0
                 ",%s", session->srv.ecdsa_key->type_c);
129
0
    }
130
6.66k
#endif
131
6.66k
    if (session->srv.rsa_key != NULL) {
132
        /* We support also the SHA2 variants */
133
6.66k
        len = strlen(hostkeys);
134
6.66k
        snprintf(hostkeys + len, sizeof(hostkeys) - len,
135
6.66k
                 ",rsa-sha2-512,rsa-sha2-256");
136
137
6.66k
        len = strlen(hostkeys);
138
6.66k
        keytype = ssh_key_type(session->srv.rsa_key);
139
140
6.66k
        snprintf(hostkeys + len, sizeof(hostkeys) - len,
141
6.66k
                 ",%s", ssh_key_type_to_char(keytype));
142
6.66k
    }
143
144
6.66k
    if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
145
81
        allowed = session->opts.wanted_methods[SSH_HOSTKEYS];
146
6.58k
    } else {
147
6.58k
        if (ssh_fips_mode()) {
148
0
            allowed = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
149
6.58k
        } else {
150
6.58k
            allowed = ssh_kex_get_default_methods(SSH_HOSTKEYS);
151
6.58k
        }
152
6.58k
    }
153
154
6.66k
    if (strlen(hostkeys) != 0) {
155
        /* It is expected for the list of allowed hostkeys to be ordered by
156
         * preference */
157
6.66k
        kept =
158
6.66k
            ssh_find_all_matching(hostkeys[0] == ',' ? hostkeys + 1 : hostkeys,
159
6.66k
                                  allowed);
160
6.66k
        if (kept == NULL) {
161
            /* Nothing was allowed */
162
0
            return -1;
163
0
        }
164
165
6.66k
        rc = ssh_options_set_algo(session,
166
6.66k
                                  SSH_HOSTKEYS,
167
6.66k
                                  kept,
168
6.66k
                                  &session->opts.wanted_methods[SSH_HOSTKEYS]);
169
6.66k
        SAFE_FREE(kept);
170
6.66k
        if (rc < 0) {
171
0
            return -1;
172
0
        }
173
6.66k
    }
174
#ifdef WITH_GSSAPI
175
    if (session->opts.gssapi_key_exchange) {
176
        ok = ssh_gssapi_init(session);
177
        if (ok != SSH_OK) {
178
            ssh_set_error_oom(session);
179
            return SSH_ERROR;
180
        }
181
182
        gssapi_algs = ssh_gssapi_kex_mechs(session);
183
        if (gssapi_algs == NULL) {
184
            return SSH_ERROR;
185
        }
186
        ssh_gssapi_free(session);
187
188
        /* Prefix the default algorithms with gsskex algs */
189
        session->opts.wanted_methods[SSH_KEX] =
190
            ssh_prefix_without_duplicates(ssh_kex_get_default_methods(SSH_KEX),
191
                                          gssapi_algs);
192
193
        if (strlen(hostkeys) == 0) {
194
            session->opts.wanted_methods[SSH_HOSTKEYS] = strdup("null");
195
        }
196
197
        SAFE_FREE(gssapi_algs);
198
    }
199
#endif /* WITH_GSSAPI */
200
201
73.3k
    for (i = 0; i < SSH_KEX_METHODS; i++) {
202
66.6k
        wanted = session->opts.wanted_methods[i];
203
66.6k
        if (wanted == NULL) {
204
33.3k
            if (ssh_fips_mode()) {
205
0
                wanted = ssh_kex_get_fips_methods(i);
206
33.3k
            } else {
207
33.3k
                wanted = ssh_kex_get_default_methods(i);
208
33.3k
            }
209
33.3k
        }
210
66.6k
        if (wanted == NULL) {
211
0
            for (j = 0; j < i; j++) {
212
0
                SAFE_FREE(server->methods[j]);
213
0
            }
214
0
            return -1;
215
0
        }
216
217
66.6k
        server->methods[i] = strdup(wanted);
218
66.6k
        if (server->methods[i] == NULL) {
219
0
            for (j = 0; j < i; j++) {
220
0
                SAFE_FREE(server->methods[j]);
221
0
            }
222
0
            return -1;
223
0
        }
224
66.6k
    }
225
226
    /* Do not append the extensions during rekey */
227
6.66k
    if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
228
81
        return SSH_OK;
229
81
    }
230
231
6.58k
    rc = ssh_kex_append_extensions(session, server);
232
6.58k
    return rc;
233
6.66k
}
234
235
0
int ssh_server_init_kex(ssh_session session) {
236
0
    int i;
237
238
0
    if (session->session_state > SSH_SESSION_STATE_BANNER_RECEIVED) {
239
0
        return SSH_ERROR;
240
0
    }
241
242
    /* free any currently-set methods: server_set_kex will allocate new ones */
243
0
    for (i = 0; i < SSH_KEX_METHODS; i++) {
244
0
        SAFE_FREE(session->next_crypto->server_kex.methods[i]);
245
0
    }
246
247
0
    return server_set_kex(session);
248
0
}
249
250
/**
251
 * @internal
252
 *
253
 * @brief Sends SSH extension information from the server to client.
254
 *
255
 * A server may send this message (`SSH_MSG_EXT_INFO`) after its first
256
 * `SSH_MSG_NEWKEYS` message or just before sending `SSH_MSG_USERAUTH_SUCCESS`
257
 * to provide additional extensions support that are not meant for an
258
 * unauthenticated client.
259
 *
260
 * If any error occurs during the packing or sending of the packet, the function
261
 * aborts to avoid partial or corrupted sends.
262
 *
263
 * @param[in] session The SSH session.
264
 *
265
 * @return `SSH_OK` on success, `SSH_ERROR` on failure.
266
 */
267
static int ssh_server_send_extensions(ssh_session session)
268
195
{
269
195
    int rc;
270
195
    const char *hostkey_algorithms = NULL;
271
272
195
    SSH_LOG(SSH_LOG_PACKET, "Sending SSH_MSG_EXT_INFO");
273
274
195
    if (session->opts.pubkey_accepted_types) {
275
0
        hostkey_algorithms = session->opts.pubkey_accepted_types;
276
195
    } else {
277
195
        if (ssh_fips_mode()) {
278
0
            hostkey_algorithms = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
279
195
        } else {
280
            /* There are no restrictions to the accepted public keys */
281
195
            hostkey_algorithms = ssh_kex_get_default_methods(SSH_HOSTKEYS);
282
195
        }
283
195
    }
284
285
195
    rc = ssh_buffer_pack(session->out_buffer,
286
195
                         "bdssss",
287
195
                         SSH2_MSG_EXT_INFO,
288
195
                         2, /* nr. of extensions */
289
195
                         "server-sig-algs",
290
195
                         hostkey_algorithms,
291
195
                         "publickey-hostbound@openssh.com",
292
195
                         "0");
293
195
    if (rc != SSH_OK) {
294
0
        goto error;
295
0
    }
296
297
195
    if (ssh_packet_send(session) == SSH_ERROR) {
298
0
        goto error;
299
0
    }
300
301
195
    return 0;
302
0
error:
303
0
    ssh_buffer_reinit(session->out_buffer);
304
305
0
    return -1;
306
195
}
307
308
5.56k
SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
309
5.56k
  (void)packet;
310
5.56k
  (void)type;
311
5.56k
  (void)user;
312
313
5.56k
  SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_KEXDH_INIT");
314
5.56k
  if(session->dh_handshake_state != DH_STATE_INIT){
315
0
    SSH_LOG(SSH_LOG_RARE,"Invalid state for SSH_MSG_KEXDH_INIT");
316
0
    session->session_state = SSH_SESSION_STATE_ERROR;
317
0
    return SSH_PACKET_USED;
318
0
  }
319
320
  /* If first_kex_packet_follows guess was wrong, ignore this message. */
321
5.56k
  if (session->first_kex_follows_guess_wrong != 0) {
322
5
    SSH_LOG(SSH_LOG_RARE, "first_kex_packet_follows guess was wrong, "
323
5
                          "ignoring first SSH_MSG_KEXDH_INIT message");
324
5
    session->first_kex_follows_guess_wrong = 0;
325
326
5
    return SSH_PACKET_USED;
327
5
  }
328
5.55k
  SSH_LOG(SSH_LOG_DEBUG, "Calling next KEXDH handler");
329
5.55k
  return SSH_PACKET_NOT_USED;
330
5.56k
}
331
332
/**
333
 * @brief Prepares server host key parameters for the key exchange process.
334
 *
335
 * Selects the appropriate private host key (RSA, ECDSA, or Ed25519) based on
336
 * the session's configured host key type, sets the corresponding @p digest
337
 * algorithm, and imports the public key blob into the Diffie-Hellman key
338
 * exchange state.
339
 *
340
 * @param[in]  session  The SSH session to which we are preparing host key
341
 * parameters.
342
 * @param[out] privkey  Pointer to receive the selected private host key.
343
 * @param[out] digest   Pointer to receive the host key digest algorithm.
344
 *
345
 * @return `SSH_OK` on success; `SSH_ERROR` on failure (invalid key type, export
346
 * failure, or DH import error).
347
 */
348
int
349
ssh_get_key_params(ssh_session session,
350
                   ssh_key *privkey,
351
                   enum ssh_digest_e *digest)
352
5.23k
{
353
5.23k
    ssh_key pubkey = NULL;
354
5.23k
    ssh_string pubkey_blob = NULL;
355
5.23k
    int rc;
356
357
5.23k
    switch(session->srv.hostkey) {
358
5.23k
      case SSH_KEYTYPE_RSA:
359
5.23k
        *privkey = session->srv.rsa_key;
360
5.23k
        break;
361
0
      case SSH_KEYTYPE_ECDSA_P256:
362
0
      case SSH_KEYTYPE_ECDSA_P384:
363
0
      case SSH_KEYTYPE_ECDSA_P521:
364
0
        *privkey = session->srv.ecdsa_key;
365
0
        break;
366
0
      case SSH_KEYTYPE_ED25519:
367
0
        *privkey = session->srv.ed25519_key;
368
0
        break;
369
0
      case SSH_KEYTYPE_RSA1:
370
0
      case SSH_KEYTYPE_UNKNOWN:
371
0
      default:
372
0
        *privkey = NULL;
373
5.23k
    }
374
375
5.23k
    *digest = session->srv.hostkey_digest;
376
5.23k
    rc = ssh_pki_export_privkey_to_pubkey(*privkey, &pubkey);
377
5.23k
    if (rc < 0) {
378
0
      ssh_set_error(session, SSH_FATAL,
379
0
          "Could not get the public key from the private key");
380
381
0
      return -1;
382
0
    }
383
384
5.23k
    rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
385
5.23k
    ssh_key_free(pubkey);
386
5.23k
    if (rc < 0) {
387
0
      ssh_set_error_oom(session);
388
0
      return -1;
389
0
    }
390
391
5.23k
    rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
392
5.23k
    SSH_STRING_FREE(pubkey_blob);
393
5.23k
    if (rc != 0) {
394
0
        ssh_set_error(session,
395
0
                      SSH_FATAL,
396
0
                      "Could not import server public key");
397
0
        return -1;
398
0
    }
399
400
5.23k
    return SSH_OK;
401
5.23k
}
402
403
/**
404
 * @internal
405
 *
406
 * @brief A function to be called each time a step has been done in the
407
 * connection.
408
 */
409
static void ssh_server_connection_callback(ssh_session session)
410
22.5k
{
411
22.5k
    int rc;
412
413
22.5k
    switch (session->session_state) {
414
0
    case SSH_SESSION_STATE_NONE:
415
0
    case SSH_SESSION_STATE_CONNECTING:
416
0
    case SSH_SESSION_STATE_SOCKET_CONNECTED:
417
0
        break;
418
6.54k
    case SSH_SESSION_STATE_BANNER_RECEIVED:
419
6.54k
        if (session->clientbanner == NULL) {
420
0
            goto error;
421
0
        }
422
6.54k
        set_status(session, 0.4f);
423
6.54k
        SSH_LOG(SSH_LOG_DEBUG,
424
6.54k
                "SSH client banner: %s", session->clientbanner);
425
426
        /* Here we analyze the different protocols the server allows. */
427
6.54k
        rc = ssh_analyze_banner(session, 1);
428
6.54k
        if (rc < 0) {
429
20
            ssh_set_error(session, SSH_FATAL,
430
20
                    "No version of SSH protocol usable (banner: %s)",
431
20
                    session->clientbanner);
432
20
            goto error;
433
20
        }
434
435
        /* from now, the packet layer is handling incoming packets */
436
6.52k
        ssh_packet_register_socket_callback(session, session->socket);
437
438
6.52k
        ssh_packet_set_default_callbacks(session);
439
6.52k
        set_status(session, 0.5f);
440
6.52k
        session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
441
6.52k
        rc = ssh_send_kex(session);
442
6.52k
        if (rc < 0) {
443
0
            goto error;
444
0
        }
445
6.52k
        break;
446
6.52k
    case SSH_SESSION_STATE_INITIAL_KEX:
447
        /* TODO: This state should disappear in favor of get_key handle */
448
0
        break;
449
5.95k
    case SSH_SESSION_STATE_KEXINIT_RECEIVED:
450
5.95k
        set_status(session, 0.6f);
451
5.95k
        if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) {
452
71
            rc = server_set_kex(session);
453
71
            if (rc == SSH_ERROR) {
454
0
                goto error;
455
0
            }
456
            /* We are in a rekeying, so we need to send the server kex */
457
71
            rc = ssh_send_kex(session);
458
71
            if (rc < 0) {
459
0
                goto error;
460
0
            }
461
71
        }
462
5.95k
        ssh_list_kex(&session->next_crypto->client_kex); // log client kex
463
5.95k
        rc = ssh_kex_select_methods(session);
464
5.95k
        if (rc < 0) {
465
419
            goto error;
466
419
        }
467
5.53k
        rc = crypt_set_algorithms_server(session);
468
5.53k
        if (rc == SSH_ERROR) {
469
0
            goto error;
470
0
        }
471
5.53k
        set_status(session, 0.8f);
472
5.53k
        session->session_state = SSH_SESSION_STATE_DH;
473
5.53k
        break;
474
5.08k
    case SSH_SESSION_STATE_DH:
475
5.08k
        if (session->dh_handshake_state == DH_STATE_FINISHED) {
476
477
5.08k
            rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN);
478
5.08k
            if (rc != SSH_OK) {
479
0
                goto error;
480
0
            }
481
482
            /*
483
             * If the client supports extension negotiation, we will send
484
             * our supported extensions now. This is the first message after
485
             * sending NEWKEYS message and after turning on crypto.
486
             */
487
5.08k
            if (session->extensions & SSH_EXT_NEGOTIATION &&
488
196
                session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
489
                /*
490
                 * Only send an SSH_MSG_EXT_INFO message the first time the
491
                 * client undergoes NEWKEYS.  It is unexpected for this message
492
                 * to be sent upon rekey, and may cause clients to log error
493
                 * messages.
494
                 *
495
                 * The session_state can not be used for this purpose because it
496
                 * is re-set to SSH_SESSION_STATE_KEXINIT_RECEIVED during rekey.
497
                 * So, use the connected flag which transitions from non-zero
498
                 * below.
499
                 *
500
                 * See also:
501
                 * - https://bugzilla.mindrot.org/show_bug.cgi?id=2929
502
                 */
503
196
                if (session->connected == 0) {
504
195
                    ssh_server_send_extensions(session);
505
195
                }
506
196
            }
507
508
5.08k
            set_status(session, 1.0f);
509
5.08k
            session->connected = 1;
510
5.08k
            session->session_state = SSH_SESSION_STATE_AUTHENTICATING;
511
5.08k
            if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
512
10
                session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
513
514
5.08k
        }
515
5.08k
        break;
516
5.08k
    case SSH_SESSION_STATE_AUTHENTICATING:
517
0
        break;
518
4.93k
    case SSH_SESSION_STATE_ERROR:
519
4.93k
        goto error;
520
0
    default:
521
0
        ssh_set_error(session, SSH_FATAL, "Invalid state %d",
522
22.5k
                      session->session_state);
523
22.5k
    }
524
525
17.1k
    return;
526
17.1k
error:
527
5.37k
    ssh_socket_close(session->socket);
528
5.37k
    session->alive = 0;
529
5.37k
    session->session_state = SSH_SESSION_STATE_ERROR;
530
5.37k
}
531
532
/**
533
 * @internal
534
 *
535
 * @brief Gets the banner from socket and saves it in session.
536
 * Updates the session state
537
 *
538
 * @param  data pointer to the beginning of header
539
 * @param  len size of the banner
540
 * @param  user is a pointer to session
541
 * @returns Number of bytes processed, or zero if the banner is not complete.
542
 */
543
static size_t callback_receive_banner(const void *data, size_t len, void *user)
544
6.58k
{
545
6.58k
    char *buffer = (char *)data;
546
6.58k
    ssh_session session = (ssh_session)user;
547
6.58k
    char *str = NULL;
548
6.58k
    size_t i;
549
6.58k
    size_t processed = 0;
550
551
76.4k
    for (i = 0; i < len; i++) {
552
76.4k
#ifdef WITH_PCAP
553
76.4k
        if (session->pcap_ctx && buffer[i] == '\n') {
554
0
            ssh_pcap_context_write(session->pcap_ctx,
555
0
                                   SSH_PCAP_DIR_IN,
556
0
                                   buffer,
557
0
                                   (uint32_t)(i + 1),
558
0
                                   (uint32_t)(i + 1));
559
0
        }
560
76.4k
#endif
561
76.4k
        if (buffer[i] == '\r') {
562
158
            buffer[i] = '\0';
563
158
        }
564
565
76.4k
        if (buffer[i] == '\n') {
566
6.54k
            buffer[i] = '\0';
567
568
6.54k
            str = strdup(buffer);
569
6.54k
            if (str == NULL) {
570
0
                session->session_state = SSH_SESSION_STATE_ERROR;
571
0
                ssh_set_error_oom(session);
572
0
                return 0;
573
0
            }
574
            /* number of bytes read */
575
6.54k
            processed = i + 1;
576
6.54k
            session->clientbanner = str;
577
6.54k
            session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED;
578
6.54k
            SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str);
579
6.54k
            session->ssh_connection_callback(session);
580
581
6.54k
            return processed;
582
6.54k
        }
583
584
69.9k
        if (i > 127) {
585
            /* Too big banner */
586
12
            session->session_state = SSH_SESSION_STATE_ERROR;
587
12
            ssh_set_error(session, SSH_FATAL,
588
12
                          "Receiving banner: too large banner");
589
590
12
            return 0;
591
12
        }
592
69.9k
    }
593
594
29
    return processed;
595
6.58k
}
596
597
/* returns 0 until the key exchange is not finished */
598
14.9k
static int ssh_server_kex_termination(void *s){
599
14.9k
  ssh_session session = s;
600
14.9k
  if (session->session_state != SSH_SESSION_STATE_ERROR &&
601
13.6k
      session->session_state != SSH_SESSION_STATE_AUTHENTICATING &&
602
10.8k
      session->session_state != SSH_SESSION_STATE_AUTHENTICATED &&
603
9.19k
      session->session_state != SSH_SESSION_STATE_DISCONNECTED)
604
9.19k
    return 0;
605
5.80k
  else
606
5.80k
    return 1;
607
14.9k
}
608
609
/* FIXME: auth_methods should be unsigned */
610
void ssh_set_auth_methods(ssh_session session, int auth_methods)
611
6.58k
{
612
    /* accept only methods in range */
613
6.58k
    session->auth.supported_methods = (uint32_t)auth_methods & 0x3fU;
614
6.58k
}
615
616
int ssh_send_issue_banner(ssh_session session, const ssh_string banner)
617
0
{
618
0
    int rc = SSH_ERROR;
619
620
0
    if (session == NULL) {
621
0
        return SSH_ERROR;
622
0
    }
623
624
0
    SSH_LOG(SSH_LOG_PACKET,
625
0
            "Sending a server issue banner");
626
627
0
    rc = ssh_buffer_pack(session->out_buffer,
628
0
                         "bSs",
629
0
                         SSH2_MSG_USERAUTH_BANNER,
630
0
                         banner,
631
0
                         "");
632
0
    if (rc != SSH_OK) {
633
0
        ssh_set_error_oom(session);
634
0
        return SSH_ERROR;
635
0
    }
636
637
0
    rc = ssh_packet_send(session);
638
0
    return rc;
639
0
}
640
641
/* Do the banner and key exchange */
642
int ssh_handle_key_exchange(ssh_session session)
643
6.58k
{
644
6.58k
    int rc;
645
646
6.58k
    if (session->session_state != SSH_SESSION_STATE_NONE) {
647
0
        goto pending;
648
0
    }
649
650
6.58k
    rc = ssh_send_banner(session, 1);
651
6.58k
    if (rc < 0) {
652
0
        return SSH_ERROR;
653
0
    }
654
655
6.58k
    session->alive = 1;
656
657
6.58k
    session->ssh_connection_callback = ssh_server_connection_callback;
658
6.58k
    session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
659
6.58k
    ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
660
6.58k
    session->socket_callbacks.data = callback_receive_banner;
661
6.58k
    session->socket_callbacks.exception = ssh_socket_exception_callback;
662
6.58k
    session->socket_callbacks.userdata = session;
663
664
6.58k
    rc = server_set_kex(session);
665
6.58k
    if (rc < 0) {
666
0
        return SSH_ERROR;
667
0
    }
668
6.58k
pending:
669
6.58k
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
670
6.58k
                                        ssh_server_kex_termination,session);
671
6.58k
    SSH_LOG(SSH_LOG_PACKET, "ssh_handle_key_exchange: current state : %d",
672
6.58k
            session->session_state);
673
6.58k
    if (rc != SSH_OK) {
674
779
        return rc;
675
779
    }
676
5.80k
    if (session->session_state == SSH_SESSION_STATE_ERROR ||
677
4.43k
        session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
678
1.36k
        return SSH_ERROR;
679
1.36k
    }
680
681
4.43k
    return SSH_OK;
682
5.80k
}
683
684
/* messages */
685
686
/** @internal
687
 * replies to an SSH_AUTH packet with a default (denied) response.
688
 */
689
4.64k
int ssh_auth_reply_default(ssh_session session,int partial) {
690
4.64k
  char methods_c[128] = {0};
691
4.64k
  int rc = SSH_ERROR;
692
693
694
4.64k
  if (session->auth.supported_methods == 0) {
695
0
    session->auth.supported_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD;
696
0
  }
697
4.64k
  if (session->auth.supported_methods & SSH_AUTH_METHOD_PUBLICKEY) {
698
0
    strncat(methods_c, "publickey,",
699
0
            sizeof(methods_c) - strlen(methods_c) - 1);
700
0
  }
701
4.64k
  if (session->auth.supported_methods & SSH_AUTH_METHOD_GSSAPI_MIC){
702
0
    strncat(methods_c,"gssapi-with-mic,",
703
0
        sizeof(methods_c) - strlen(methods_c) - 1);
704
0
  }
705
  /* Check if GSSAPI Key exchange was performed */
706
4.64k
  if (session->auth.supported_methods & SSH_AUTH_METHOD_GSSAPI_KEYEX) {
707
0
      if (ssh_kex_is_gss(session->current_crypto)) {
708
0
          strncat(methods_c,
709
0
                  "gssapi-keyex,",
710
0
                  sizeof(methods_c) - strlen(methods_c) - 1);
711
0
      }
712
0
  }
713
4.64k
  if (session->auth.supported_methods & SSH_AUTH_METHOD_INTERACTIVE) {
714
0
    strncat(methods_c, "keyboard-interactive,",
715
0
            sizeof(methods_c) - strlen(methods_c) - 1);
716
0
  }
717
4.64k
  if (session->auth.supported_methods & SSH_AUTH_METHOD_PASSWORD) {
718
0
    strncat(methods_c, "password,",
719
0
            sizeof(methods_c) - strlen(methods_c) - 1);
720
0
  }
721
4.64k
  if (session->auth.supported_methods & SSH_AUTH_METHOD_HOSTBASED) {
722
0
    strncat(methods_c, "hostbased,",
723
0
            sizeof(methods_c) - strlen(methods_c) - 1);
724
0
  }
725
726
4.64k
  if (methods_c[0] == '\0' || methods_c[strlen(methods_c)-1] != ',') {
727
4.64k
      return SSH_ERROR;
728
4.64k
  }
729
730
  /* Strip the comma. */
731
0
  methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure there is at
732
733
0
  SSH_LOG(SSH_LOG_PACKET,
734
0
      "Sending a auth failure. methods that can continue: %s", methods_c);
735
736
0
  rc = ssh_buffer_pack(session->out_buffer,
737
0
                       "bsb",
738
0
                       SSH2_MSG_USERAUTH_FAILURE,
739
0
                       methods_c,
740
0
                       partial ? 1 : 0);
741
0
  if (rc != SSH_OK){
742
0
      ssh_set_error_oom(session);
743
0
      return SSH_ERROR;
744
0
  }
745
0
  rc = ssh_packet_send(session);
746
0
  return rc;
747
0
}
748
749
/**
750
 * @internal
751
 *
752
 * @brief Sends default refusal for a channel open request.
753
 *
754
 * Default handler that rejects incoming SSH channel open requests by sending
755
 * a `SSH2_MSG_CHANNEL_OPEN_FAILURE` packet with "administratively prohibited"
756
 * reason code. Used when no custom channel open handler is registered.
757
 *
758
 * @param[in] msg The SSH message containing the channel open request details.
759
 *
760
 * @return `SSH_OK` on successful packet send; `SSH_ERROR` on buffer allocation
761
 *         or packet send failure.
762
 */
763
463
static int ssh_message_channel_request_open_reply_default(ssh_message msg) {
764
463
    int rc;
765
766
463
    SSH_LOG(SSH_LOG_FUNCTIONS, "Refusing a channel");
767
768
463
    rc = ssh_buffer_pack(msg->session->out_buffer,
769
463
                         "bdddd",
770
463
                         SSH2_MSG_CHANNEL_OPEN_FAILURE,
771
463
                         msg->channel_request_open.sender,
772
463
                         SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
773
463
                         0,    /* reason is empty string */
774
463
                         0);   /* language string */
775
463
    if (rc != SSH_OK){
776
0
        ssh_set_error_oom(msg->session);
777
0
        return SSH_ERROR;
778
0
    }
779
780
463
    rc = ssh_packet_send(msg->session);
781
463
    return rc;
782
463
}
783
784
/**
785
 * @internal
786
 *
787
 * @brief Sends default refusal for a channel request.
788
 *
789
 * Default handler that rejects incoming SSH channel requests. If the client
790
 * requested a reply (`want_reply`), sends `SSH2_MSG_CHANNEL_FAILURE` to the
791
 * specific channel. If no reply requested, logs the refusal and returns
792
 * success.
793
 *
794
 * @param[in] msg The SSH message containing the channel request details.
795
 *
796
 * @return `SSH_OK` on success; `SSH_ERROR` if buffer allocation or packet send
797
 * fails.
798
 */
799
713
static int ssh_message_channel_request_reply_default(ssh_message msg) {
800
713
  uint32_t channel;
801
713
  int rc;
802
803
713
  if (msg->channel_request.want_reply) {
804
467
    channel = msg->channel_request.channel->remote_channel;
805
806
467
    SSH_LOG(SSH_LOG_PACKET,
807
467
        "Sending a default channel_request denied to channel %" PRIu32, channel);
808
809
467
    rc = ssh_buffer_pack(msg->session->out_buffer,
810
467
                         "bd",
811
467
                         SSH2_MSG_CHANNEL_FAILURE,
812
467
                         channel);
813
467
    if (rc != SSH_OK){
814
0
        ssh_set_error_oom(msg->session);
815
0
        return SSH_ERROR;
816
0
    }
817
467
    return ssh_packet_send(msg->session);
818
467
  }
819
820
246
  SSH_LOG(SSH_LOG_PACKET,
821
246
      "The client doesn't want to know the request failed!");
822
823
246
  return SSH_OK;
824
713
}
825
826
173
static int ssh_message_service_request_reply_default(ssh_message msg) {
827
  /* The only return code accepted by specifications are success or disconnect */
828
173
  return ssh_message_service_reply_success(msg);
829
173
}
830
831
/**
832
 * @brief   Sends `SSH2_MSG_SERVICE_ACCEPT` to the client
833
 *
834
 * @param msg The message to reply to
835
 *
836
 * @returns `SSH_OK` when success otherwise `SSH_ERROR`
837
 */
838
int ssh_message_service_reply_success(ssh_message msg)
839
173
{
840
173
    ssh_session session = NULL;
841
173
    int rc;
842
843
173
    if (msg == NULL) {
844
0
        return SSH_ERROR;
845
0
    }
846
173
    session = msg->session;
847
848
173
    SSH_LOG(SSH_LOG_PACKET,
849
173
            "Sending a SERVICE_ACCEPT for service %s", msg->service_request.service);
850
851
173
    rc = ssh_buffer_pack(session->out_buffer,
852
173
                         "bs",
853
173
                         SSH2_MSG_SERVICE_ACCEPT,
854
173
                         msg->service_request.service);
855
173
    if (rc != SSH_OK){
856
0
        ssh_set_error_oom(session);
857
0
        return SSH_ERROR;
858
0
    }
859
173
    rc = ssh_packet_send(msg->session);
860
173
    return rc;
861
173
}
862
863
/**
864
 * @brief Send a global request success message
865
 *
866
 * @param msg The message
867
 *
868
 * @param bound_port The remote bind port
869
 *
870
 * @returns `SSH_OK` on success, otherwise `SSH_ERROR`
871
 */
872
34
int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_port) {
873
34
    int rc;
874
875
34
    SSH_LOG(SSH_LOG_FUNCTIONS, "Accepting a global request");
876
877
34
    if (msg->global_request.want_reply) {
878
34
        if (ssh_buffer_add_u8(msg->session->out_buffer
879
34
                    , SSH2_MSG_REQUEST_SUCCESS) < 0) {
880
0
            goto error;
881
0
        }
882
883
34
        if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
884
0
                                && msg->global_request.bind_port == 0) {
885
0
            rc = ssh_buffer_pack(msg->session->out_buffer, "d", bound_port);
886
0
            if (rc != SSH_OK) {
887
0
                ssh_set_error_oom(msg->session);
888
0
                goto error;
889
0
            }
890
0
        }
891
892
34
        return ssh_packet_send(msg->session);
893
34
    }
894
895
0
    if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
896
0
                                && msg->global_request.bind_port == 0) {
897
0
        SSH_LOG(SSH_LOG_PACKET,
898
0
                "The client doesn't want to know the remote port!");
899
0
    }
900
901
0
    return SSH_OK;
902
0
error:
903
0
    return SSH_ERROR;
904
34
}
905
906
/**
907
 * @internal
908
 *
909
 * @brief Sends default refusal for a global request.
910
 *
911
 * Default handler that rejects incoming SSH global requests. If the client
912
 * requested a reply (`want_reply`), sends `SSH2_MSG_REQUEST_FAILURE`. If no
913
 * reply requested, logs the refusal and returns success immediately.
914
 *
915
 * @param[in] msg The SSH message containing the global request details.
916
 *
917
 * @return `SSH_OK` on success; `SSH_ERROR` if buffer allocation or packet send
918
 * fails.
919
 */
920
51
static int ssh_message_global_request_reply_default(ssh_message msg) {
921
51
    SSH_LOG(SSH_LOG_FUNCTIONS, "Refusing a global request");
922
923
51
    if (msg->global_request.want_reply) {
924
29
        if (ssh_buffer_add_u8(msg->session->out_buffer
925
29
                    , SSH2_MSG_REQUEST_FAILURE) < 0) {
926
0
            goto error;
927
0
        }
928
29
        return ssh_packet_send(msg->session);
929
29
    }
930
22
    SSH_LOG(SSH_LOG_PACKET,
931
22
            "The client doesn't want to know the request failed!");
932
933
22
    return SSH_OK;
934
0
error:
935
0
    return SSH_ERROR;
936
51
}
937
938
3.92k
int ssh_message_reply_default(ssh_message msg) {
939
3.92k
  if (msg == NULL) {
940
0
    return -1;
941
0
  }
942
943
3.92k
  switch(msg->type) {
944
2.52k
    case SSH_REQUEST_AUTH:
945
2.52k
      return ssh_auth_reply_default(msg->session, 0);
946
463
    case SSH_REQUEST_CHANNEL_OPEN:
947
463
      return ssh_message_channel_request_open_reply_default(msg);
948
713
    case SSH_REQUEST_CHANNEL:
949
713
      return ssh_message_channel_request_reply_default(msg);
950
173
    case SSH_REQUEST_SERVICE:
951
173
      return ssh_message_service_request_reply_default(msg);
952
51
    case SSH_REQUEST_GLOBAL:
953
51
      return ssh_message_global_request_reply_default(msg);
954
0
    default:
955
0
      SSH_LOG(SSH_LOG_PACKET,
956
0
          "Don't know what to default reply to %d type",
957
0
          msg->type);
958
0
      break;
959
3.92k
  }
960
961
0
  return -1;
962
3.92k
}
963
964
/**
965
 * @brief Gets the service name from the service request message
966
 *
967
 * @param msg The service request message
968
 *
969
 * @returns the service name from the message
970
 */
971
0
const char *ssh_message_service_service(ssh_message msg){
972
0
  if (msg == NULL) {
973
0
    return NULL;
974
0
  }
975
0
  return msg->service_request.service;
976
0
}
977
978
0
const char *ssh_message_auth_user(ssh_message msg) {
979
0
  if (msg == NULL) {
980
0
    return NULL;
981
0
  }
982
983
0
  return msg->auth_request.username;
984
0
}
985
986
0
const char *ssh_message_auth_password(ssh_message msg){
987
0
  if (msg == NULL) {
988
0
    return NULL;
989
0
  }
990
991
0
  return msg->auth_request.password;
992
0
}
993
994
0
ssh_key ssh_message_auth_pubkey(ssh_message msg) {
995
0
  if (msg == NULL) {
996
0
    return NULL;
997
0
  }
998
999
0
  return msg->auth_request.pubkey;
1000
0
}
1001
1002
0
ssh_public_key ssh_message_auth_publickey(ssh_message msg){
1003
0
  if (msg == NULL) {
1004
0
    return NULL;
1005
0
  }
1006
1007
0
  return ssh_pki_convert_key_to_publickey(msg->auth_request.pubkey);
1008
0
}
1009
1010
0
enum ssh_publickey_state_e ssh_message_auth_publickey_state(ssh_message msg){
1011
0
  if (msg == NULL) {
1012
0
      return -1;
1013
0
    }
1014
0
    return msg->auth_request.signature_state;
1015
0
}
1016
1017
/**
1018
 *  @brief Check if the message is a keyboard-interactive response
1019
 *
1020
 *  @param msg The message to check
1021
 *
1022
 *  @returns 1 if the message is a response, otherwise 0
1023
 */
1024
0
int ssh_message_auth_kbdint_is_response(ssh_message msg) {
1025
0
  if (msg == NULL) {
1026
0
    return -1;
1027
0
  }
1028
1029
0
  return msg->auth_request.kbdint_response != 0;
1030
0
}
1031
1032
/* FIXME: methods should be unsigned */
1033
/**
1034
 * @brief Sets the supported authentication methods to a message
1035
 *
1036
 * @param msg The message
1037
 *
1038
 * @param methods Methods to set to the message.
1039
 * The supported methods are listed in ssh_set_auth_methods
1040
 * @see ssh_set_auth_methods
1041
 *
1042
 * @returns 0 on success, otherwise -1
1043
 */
1044
0
int ssh_message_auth_set_methods(ssh_message msg, int methods) {
1045
0
  if (msg == NULL || msg->session == NULL) {
1046
0
    return -1;
1047
0
  }
1048
1049
0
  if (methods < 0) {
1050
0
      return -1;
1051
0
  }
1052
1053
0
  msg->session->auth.supported_methods = (uint32_t)methods;
1054
1055
0
  return 0;
1056
0
}
1057
1058
/**
1059
 * @brief Sends an interactive authentication request message.
1060
 *
1061
 * Builds and sends an `SSH2_MSG_USERAUTH_INFO_REQUEST` packet containing the
1062
 * given name and @p instruction, followed by a number of @p prompts with
1063
 * associated @p echo flags to control whether user input is echoed.
1064
 * It initializes the keyboard-interactive state in the session.
1065
 *
1066
 * @param[in]  msg          The SSH message representing the client
1067
 *                          authentication request.
1068
 * @param[in]  name         The name of the authentication request.
1069
 * @param[in]  instruction  Instruction string with information for the user.
1070
 * @param[in]  num_prompts  Number of prompts to send. The arrays prompts and
1071
 *                          echo must both have num_prompts elements.
1072
 * @param[in]  prompts      Array of @p num_prompts prompt strings to display.
1073
 * @param[in]  echo         Array of num_prompts boolean values (0 or 1). A
1074
 *                          non-zero value means the user input for that prompt
1075
 *                          is echoed (visible); 0 means the input is hidden
1076
 *                          (typically for passwords).
1077
 *
1078
 * @return `SSH_OK` on successful send; `SSH_ERROR` on failure.
1079
 */
1080
int ssh_message_auth_interactive_request(ssh_message msg, const char *name,
1081
                            const char *instruction, unsigned int num_prompts,
1082
0
                            const char **prompts, char *echo) {
1083
0
  int rc;
1084
0
  unsigned int i = 0;
1085
1086
0
  if(name == NULL || instruction == NULL) {
1087
0
    return SSH_ERROR;
1088
0
  }
1089
0
  if(num_prompts > 0 && (prompts == NULL || echo == NULL)) {
1090
0
    return SSH_ERROR;
1091
0
  }
1092
1093
0
  rc = ssh_buffer_pack(msg->session->out_buffer,
1094
0
                       "bsssd",
1095
0
                       SSH2_MSG_USERAUTH_INFO_REQUEST,
1096
0
                       name,
1097
0
                       instruction,
1098
0
                       "",           /* language tag */
1099
0
                       num_prompts);
1100
0
  if (rc != SSH_OK){
1101
0
    ssh_set_error_oom(msg->session);
1102
0
    return SSH_ERROR;
1103
0
  }
1104
1105
0
  for(i = 0; i < num_prompts; i++) {
1106
0
    rc = ssh_buffer_pack(msg->session->out_buffer,
1107
0
                         "sb",
1108
0
                         prompts[i],
1109
0
                         echo[i] ? 1 : 0);
1110
0
    if (rc != SSH_OK){
1111
0
        ssh_set_error_oom(msg->session);
1112
0
        return SSH_ERROR;
1113
0
    }
1114
0
  }
1115
1116
0
  rc = ssh_packet_send(msg->session);
1117
1118
  /* fill in the kbdint structure */
1119
0
  if (msg->session->kbdint == NULL) {
1120
0
    SSH_LOG(SSH_LOG_DEBUG, "Warning: Got a keyboard-interactive response "
1121
0
                           "but it seems we didn't send the request.");
1122
1123
0
    msg->session->kbdint = ssh_kbdint_new();
1124
0
    if (msg->session->kbdint == NULL) {
1125
0
      ssh_set_error_oom(msg->session);
1126
1127
0
      return SSH_ERROR;
1128
0
    }
1129
0
  } else {
1130
0
    ssh_kbdint_clean(msg->session->kbdint);
1131
0
  }
1132
1133
0
  msg->session->kbdint->name = strdup(name);
1134
0
  if(msg->session->kbdint->name == NULL) {
1135
0
      ssh_set_error_oom(msg->session);
1136
0
      ssh_kbdint_free(msg->session->kbdint);
1137
0
      msg->session->kbdint = NULL;
1138
0
      return SSH_PACKET_USED;
1139
0
  }
1140
0
  msg->session->kbdint->instruction = strdup(instruction);
1141
0
  if(msg->session->kbdint->instruction == NULL) {
1142
0
      ssh_set_error_oom(msg->session);
1143
0
      ssh_kbdint_free(msg->session->kbdint);
1144
0
      msg->session->kbdint = NULL;
1145
0
      return SSH_PACKET_USED;
1146
0
  }
1147
1148
0
  msg->session->kbdint->nprompts = num_prompts;
1149
0
  if(num_prompts > 0) {
1150
0
    msg->session->kbdint->prompts = calloc(num_prompts, sizeof(char *));
1151
0
    if (msg->session->kbdint->prompts == NULL) {
1152
0
      msg->session->kbdint->nprompts = 0;
1153
0
      ssh_set_error_oom(msg->session);
1154
0
      ssh_kbdint_free(msg->session->kbdint);
1155
0
      msg->session->kbdint = NULL;
1156
0
      return SSH_ERROR;
1157
0
    }
1158
0
    msg->session->kbdint->echo = calloc(num_prompts, sizeof(unsigned char));
1159
0
    if (msg->session->kbdint->echo == NULL) {
1160
0
      ssh_set_error_oom(msg->session);
1161
0
      ssh_kbdint_free(msg->session->kbdint);
1162
0
      msg->session->kbdint = NULL;
1163
0
      return SSH_ERROR;
1164
0
    }
1165
0
    for (i = 0; i < num_prompts; i++) {
1166
0
      msg->session->kbdint->echo[i] = echo[i];
1167
0
      msg->session->kbdint->prompts[i] = strdup(prompts[i]);
1168
0
      if (msg->session->kbdint->prompts[i] == NULL) {
1169
0
        ssh_set_error_oom(msg->session);
1170
0
        msg->session->kbdint->nprompts = i;
1171
0
        ssh_kbdint_free(msg->session->kbdint);
1172
0
        msg->session->kbdint = NULL;
1173
0
        return SSH_PACKET_USED;
1174
0
      }
1175
0
    }
1176
0
  } else {
1177
0
    msg->session->kbdint->prompts = NULL;
1178
0
    msg->session->kbdint->echo = NULL;
1179
0
  }
1180
0
  msg->session->auth.state = SSH_AUTH_STATE_INFO;
1181
1182
0
  return rc;
1183
0
}
1184
1185
/**
1186
 * @brief Sends `SSH2_MSG_USERAUTH_SUCCESS` or `SSH2_MSG_USERAUTH_FAILURE`
1187
 * message depending on the success of the authentication method
1188
 *
1189
 * @param session The session to reply to
1190
 *
1191
 * @param partial Denotes if the authentication process was partially completed
1192
 * (unsuccessful)
1193
 *
1194
 * @returns `SSH_OK` on success, otherwise `SSH_ERROR`
1195
 */
1196
int ssh_auth_reply_success(ssh_session session, int partial)
1197
4.20k
{
1198
4.20k
    struct ssh_crypto_struct *crypto = NULL;
1199
4.20k
    int r;
1200
1201
4.20k
    if (session == NULL) {
1202
0
        return SSH_ERROR;
1203
0
    }
1204
1205
4.20k
    if (partial) {
1206
2.11k
        return ssh_auth_reply_default(session, partial);
1207
2.11k
    }
1208
1209
2.09k
    r = ssh_buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS);
1210
2.09k
    if (r < 0) {
1211
0
        return SSH_ERROR;
1212
0
    }
1213
1214
2.09k
    r = ssh_packet_send(session);
1215
1216
    /*
1217
     * Consider the session as having been authenticated only after sending
1218
     * the `USERAUTH_SUCCESS` message.  Setting these flags after
1219
     * ssh_packet_send ensures that a rekey is not triggered prematurely,
1220
     * causing the message to be queued.
1221
     */
1222
2.09k
    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
1223
2.09k
    session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
1224
1225
2.09k
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
1226
2.09k
    if (crypto != NULL && crypto->delayed_compress_out) {
1227
0
        SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
1228
0
        crypto->do_compress_out = 1;
1229
0
    }
1230
1231
2.09k
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
1232
2.09k
    if (crypto != NULL && crypto->delayed_compress_in) {
1233
0
        SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
1234
0
        crypto->do_compress_in = 1;
1235
0
    }
1236
2.09k
    return r;
1237
2.09k
}
1238
1239
/**
1240
 * @brief Replies to an authentication request with success.
1241
 *
1242
 * Sends an authentication success message (`SSH2_MSG_USERAUTH_SUCCESS`) to the
1243
 * client, or a partial success if further authentication steps are required.
1244
 *
1245
 * @param[in] msg     The SSH authentication message being handled.
1246
 * @param[in] partial Set to nonzero if partial success (more auth needed), zero
1247
 * for full success.
1248
 *
1249
 * @return `SSH_OK` on success, `SSH_ERROR` if msg is NULL or on send failure.
1250
 */
1251
4.20k
int ssh_message_auth_reply_success(ssh_message msg, int partial) {
1252
4.20k
  if(msg == NULL)
1253
0
    return SSH_ERROR;
1254
4.20k
  return ssh_auth_reply_success(msg->session, partial);
1255
4.20k
}
1256
1257
/**
1258
 * @brief Answer `SSH2_MSG_USERAUTH_PK_OK` to a pubkey authentication request
1259
 *
1260
 * @param msg The message
1261
 *
1262
 * @param algo The algorithm of the accepted public key
1263
 *
1264
 * @param pubkey The accepted public key
1265
 *
1266
 * @returns `SSH_OK` on success, otherwise `SSH_ERROR`
1267
 */
1268
0
int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_string pubkey) {
1269
0
    int rc;
1270
0
    if (msg == NULL) {
1271
0
        return SSH_ERROR;
1272
0
    }
1273
1274
0
    rc = ssh_buffer_pack(msg->session->out_buffer,
1275
0
                         "bSS",
1276
0
                         SSH2_MSG_USERAUTH_PK_OK,
1277
0
                         algo,
1278
0
                         pubkey);
1279
0
    if(rc != SSH_OK){
1280
0
        ssh_set_error_oom(msg->session);
1281
0
        return SSH_ERROR;
1282
0
    }
1283
1284
0
    rc = ssh_packet_send(msg->session);
1285
0
    return rc;
1286
0
}
1287
1288
/**
1289
 * @brief Answer `SSH2_MSG_USERAUTH_PK_OK` to a pubkey authentication request
1290
 *
1291
 * @param msg The message
1292
 *
1293
 * @returns `SSH_OK` on success, otherwise `SSH_ERROR`
1294
 */
1295
int ssh_message_auth_reply_pk_ok_simple(ssh_message msg)
1296
0
{
1297
0
    ssh_string algo = NULL;
1298
0
    ssh_string pubkey_blob = NULL;
1299
0
    int ret;
1300
1301
0
    algo = ssh_string_from_char(msg->auth_request.sigtype);
1302
0
    if (algo == NULL) {
1303
0
        return SSH_ERROR;
1304
0
    }
1305
1306
0
    ret = ssh_pki_export_pubkey_blob(msg->auth_request.pubkey, &pubkey_blob);
1307
0
    if (ret < 0) {
1308
0
        SSH_STRING_FREE(algo);
1309
0
        return SSH_ERROR;
1310
0
    }
1311
1312
0
    ret = ssh_message_auth_reply_pk_ok(msg, algo, pubkey_blob);
1313
1314
0
    SSH_STRING_FREE(algo);
1315
0
    SSH_STRING_FREE(pubkey_blob);
1316
1317
0
    return ret;
1318
0
}
1319
1320
/**
1321
 * @brief Get the originator address from the channel open message.
1322
 *
1323
 * @param[in] msg        The message.
1324
 *
1325
 * @return               The originator address, or NULL.
1326
 */
1327
0
const char *ssh_message_channel_request_open_originator(ssh_message msg){
1328
0
    return msg->channel_request_open.originator;
1329
0
}
1330
1331
/**
1332
 * @brief Get the originator port from the channel open message.
1333
 *
1334
 * @param[in] msg        The message.
1335
 *
1336
 * @return               The originator port.
1337
 */
1338
0
int ssh_message_channel_request_open_originator_port(ssh_message msg){
1339
0
    return msg->channel_request_open.originator_port;
1340
0
}
1341
1342
/**
1343
 * @brief Get the destination address from the channel open message.
1344
 *
1345
 * @param[in] msg        The message.
1346
 *
1347
 * @return               The destination address, or NULL.
1348
 */
1349
0
const char *ssh_message_channel_request_open_destination(ssh_message msg){
1350
0
    return msg->channel_request_open.destination;
1351
0
}
1352
1353
/**
1354
 * @brief Get the destination port from the channel open message.
1355
 *
1356
 * @param[in] msg        The message.
1357
 *
1358
 * @return               The destination port.
1359
 */
1360
0
int ssh_message_channel_request_open_destination_port(ssh_message msg){
1361
0
    return msg->channel_request_open.destination_port;
1362
0
}
1363
1364
/**
1365
 * @brief Get the channel associated with the message.
1366
 *
1367
 * @param[in] msg        The message.
1368
 *
1369
 * @return               The channel associated with the message.
1370
 */
1371
0
ssh_channel ssh_message_channel_request_channel(ssh_message msg){
1372
0
    return msg->channel_request.channel;
1373
0
}
1374
1375
/**
1376
 * @brief Get the terminal type from the message.
1377
 *
1378
 * @param[in] msg        The message.
1379
 *
1380
 * @return               The terminal type (e.g. "xterm"), or NULL.
1381
 *
1382
 * @deprecated This function should not be used anymore as there is a
1383
 * callback based server implementation function channel_pty_request_function.
1384
 *
1385
 * @see channel_pty_request_function.
1386
 */
1387
0
const char *ssh_message_channel_request_pty_term(ssh_message msg){
1388
0
    return msg->channel_request.TERM;
1389
0
}
1390
1391
/**
1392
 * @brief Get the terminal width from the message.
1393
 *
1394
 * @param[in] msg        The message.
1395
 *
1396
 * @return               The terminal width in characters.
1397
 *
1398
 * @deprecated This function should not be used anymore as there is a
1399
 * callback based server implementation function channel_pty_request_function.
1400
 *
1401
 * @see channel_pty_request_function.
1402
 */
1403
0
int ssh_message_channel_request_pty_width(ssh_message msg){
1404
0
    return msg->channel_request.width;
1405
0
}
1406
1407
/**
1408
 * @brief Get the terminal height from the message.
1409
 *
1410
 * @param[in] msg        The message.
1411
 *
1412
 * @return               The terminal height in characters.
1413
 *
1414
 * @deprecated This function should not be used anymore as there is a
1415
 * callback based server implementation function channel_pty_request_function.
1416
 *
1417
 * @see channel_pty_request_function.
1418
 */
1419
0
int ssh_message_channel_request_pty_height(ssh_message msg){
1420
0
    return msg->channel_request.height;
1421
0
}
1422
1423
/**
1424
 * @brief Get the terminal pixel width from the message.
1425
 *
1426
 * @param[in] msg        The message.
1427
 *
1428
 * @return               The pixel width.
1429
 *
1430
 * @deprecated This function should not be used anymore as there is a
1431
 * callback based server implementation function channel_pty_request_function.
1432
 *
1433
 * @see channel_pty_request_function.
1434
 */
1435
0
int ssh_message_channel_request_pty_pxwidth(ssh_message msg){
1436
0
    return msg->channel_request.pxwidth;
1437
0
}
1438
1439
/**
1440
 * @brief Get the terminal pixel height from the message.
1441
 *
1442
 * @param[in] msg        The message.
1443
 *
1444
 * @return               The pixel height.
1445
 *
1446
 * @deprecated This function should not be used anymore as there is a
1447
 * callback based server implementation function channel_pty_request_function.
1448
 *
1449
 * @see channel_pty_request_function.
1450
 */
1451
0
int ssh_message_channel_request_pty_pxheight(ssh_message msg){
1452
0
    return msg->channel_request.pxheight;
1453
0
}
1454
1455
/**
1456
 * @brief Get the name of the environment variable from the message.
1457
 *
1458
 * @param[in] msg        The message.
1459
 *
1460
 * @return               The variable name, or NULL.
1461
 */
1462
0
const char *ssh_message_channel_request_env_name(ssh_message msg){
1463
0
    return msg->channel_request.var_name;
1464
0
}
1465
1466
/**
1467
 * @brief Get the value of the environment variable from the message.
1468
 *
1469
 * @param[in] msg        The message.
1470
 *
1471
 * @return               The variable value, or NULL.
1472
 */
1473
0
const char *ssh_message_channel_request_env_value(ssh_message msg){
1474
0
    return msg->channel_request.var_value;
1475
0
}
1476
1477
/**
1478
 * @brief Get the command from a channel request message.
1479
 *
1480
 * @param[in] msg        The message.
1481
 *
1482
 * @return               The command, or NULL.
1483
 */
1484
0
const char *ssh_message_channel_request_command(ssh_message msg){
1485
0
    return msg->channel_request.command;
1486
0
}
1487
1488
/**
1489
 * @brief Get the subsystem from a channel request message.
1490
 *
1491
 * @param[in] msg        The message.
1492
 *
1493
 * @return               The subsystem, or NULL.
1494
 */
1495
0
const char *ssh_message_channel_request_subsystem(ssh_message msg){
1496
0
    return msg->channel_request.subsystem;
1497
0
}
1498
1499
/**
1500
 * @brief Check if the X11 request is for a single connection.
1501
 *
1502
 * @param[in] msg        The message.
1503
 *
1504
 * @return               1 if single connection, 0 otherwise.
1505
 *
1506
 * @deprecated This function should not be used anymore as there is a
1507
 * callback based server implementation function
1508
 * channel_open_request_x11_function.
1509
 *
1510
 * @see channel_open_request_x11_function.
1511
 */
1512
0
int ssh_message_channel_request_x11_single_connection(ssh_message msg){
1513
0
    return msg->channel_request.x11_single_connection ? 1 : 0;
1514
0
}
1515
1516
/**
1517
 * @brief Get the X11 authentication protocol from the message.
1518
 *
1519
 * @param[in] msg        The message.
1520
 *
1521
 * @return               The authentication protocol, or NULL.
1522
 *
1523
 * @deprecated This function should not be used anymore as there is a
1524
 * callback based server implementation function
1525
 * channel_open_request_x11_function.
1526
 *
1527
 * @see channel_open_request_x11_function.
1528
 */
1529
0
const char *ssh_message_channel_request_x11_auth_protocol(ssh_message msg){
1530
0
    return msg->channel_request.x11_auth_protocol;
1531
0
}
1532
1533
/**
1534
 * @brief Get the X11 authentication cookie from the message.
1535
 *
1536
 * @param[in] msg        The message.
1537
 *
1538
 * @return               The authentication cookie, or NULL.
1539
 *
1540
 * @deprecated This function should not be used anymore as there is a
1541
 * callback based server implementation function
1542
 * channel_open_request_x11_function.
1543
 *
1544
 * @see channel_open_request_x11_function.
1545
 */
1546
0
const char *ssh_message_channel_request_x11_auth_cookie(ssh_message msg){
1547
0
    return msg->channel_request.x11_auth_cookie;
1548
0
}
1549
1550
/**
1551
 * @brief Get the X11 screen number from the message.
1552
 *
1553
 * @param[in] msg        The message.
1554
 *
1555
 * @return               The screen number.
1556
 *
1557
 * @deprecated This function should not be used anymore as there is a
1558
 * callback based server implementation function
1559
 * channel_open_request_x11_function.
1560
 *
1561
 * @see channel_open_request_x11_function.
1562
 */
1563
0
int ssh_message_channel_request_x11_screen_number(ssh_message msg){
1564
0
    return msg->channel_request.x11_screen_number;
1565
0
}
1566
1567
/**
1568
 * @brief Get the bind address from the global request message.
1569
 *
1570
 * @param[in] msg        The message.
1571
 *
1572
 * @return               The bind address, or NULL.
1573
 */
1574
0
const char *ssh_message_global_request_address(ssh_message msg){
1575
0
    return msg->global_request.bind_address;
1576
0
}
1577
1578
/**
1579
 * @brief Get the bind port from the global request message.
1580
 *
1581
 * @param[in] msg        The message.
1582
 *
1583
 * @return               The bind port.
1584
 */
1585
0
int ssh_message_global_request_port(ssh_message msg){
1586
0
    return msg->global_request.bind_port;
1587
0
}
1588
1589
/** @brief defines the ssh_message callback
1590
 * @param session the current ssh session
1591
 * @param[in] ssh_bind_message_callback a function pointer to a callback taking the
1592
 * current ssh session and received message as parameters. the function returns
1593
 * 0 if the message has been parsed and treated successfully, 1 otherwise (libssh
1594
 * must take care of the response).
1595
 * @param[in] data void pointer to be passed to callback functions
1596
 */
1597
void ssh_set_message_callback(ssh_session session,
1598
        int(*ssh_bind_message_callback)(ssh_session session, ssh_message msg, void *data),
1599
0
        void *data) {
1600
0
  session->ssh_message_callback = ssh_bind_message_callback;
1601
0
  session->ssh_message_callback_data = data;
1602
0
}
1603
1604
/**
1605
 * @brief Execute callbacks for the messages in the queue.
1606
 *
1607
 * @param[in] session    The session.
1608
 *
1609
 * @return               `SSH_OK` on success, `SSH_ERROR` on error.
1610
 */
1611
0
int ssh_execute_message_callbacks(ssh_session session){
1612
0
  ssh_message msg=NULL;
1613
0
  int ret;
1614
0
  ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING);
1615
0
  if(!session->ssh_message_list)
1616
0
    return SSH_OK;
1617
0
  if(session->ssh_message_callback){
1618
0
    while((msg=ssh_message_pop_head(session)) != NULL) {
1619
0
      ret=session->ssh_message_callback(session,msg,
1620
0
                                        session->ssh_message_callback_data);
1621
0
      if(ret==1){
1622
0
        ret = ssh_message_reply_default(msg);
1623
0
        ssh_message_free(msg);
1624
0
        if(ret != SSH_OK)
1625
0
          return ret;
1626
0
      } else {
1627
0
        ssh_message_free(msg);
1628
0
      }
1629
0
    }
1630
0
  } else {
1631
0
    while((msg=ssh_message_pop_head(session)) != NULL) {
1632
0
      ret = ssh_message_reply_default(msg);
1633
0
      ssh_message_free(msg);
1634
0
      if(ret != SSH_OK)
1635
0
        return ret;
1636
0
    }
1637
0
  }
1638
0
  return SSH_OK;
1639
0
}
1640
1641
/**
1642
 * @brief Sends a keepalive message to the session
1643
 *
1644
 * @param session   The session to send the message to
1645
 *
1646
 * @returns `SSH_OK`
1647
 */
1648
int ssh_send_keepalive(ssh_session session)
1649
0
{
1650
    /* Client denies the request, so the error code is not meaningful */
1651
0
    (void)ssh_global_request(session, "keepalive@openssh.com", NULL, 1);
1652
1653
0
    return SSH_OK;
1654
0
}
1655
1656
/** @} */