Coverage Report

Created: 2025-07-04 06:38

/src/libssh/src/bind.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * bind.c : all ssh_bind functions
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2004-2005 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
25
#include "config.h"
26
27
#include <errno.h>
28
#include <fcntl.h>
29
#include <stdio.h>
30
#include <string.h>
31
#include <stdlib.h>
32
33
#include "libssh/priv.h"
34
#include "libssh/bind.h"
35
#include "libssh/libssh.h"
36
#include "libssh/server.h"
37
#include "libssh/pki.h"
38
#include "libssh/buffer.h"
39
#include "libssh/socket.h"
40
#include "libssh/session.h"
41
#include "libssh/token.h"
42
43
/**
44
 * @addtogroup libssh_server
45
 *
46
 * @{
47
 */
48
49
50
#ifdef _WIN32
51
#include <io.h>
52
#include <winsock2.h>
53
#include <ws2tcpip.h>
54
55
/*
56
 * <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
57
 * available on some platforms like MinGW.
58
 */
59
#ifdef HAVE_WSPIAPI_H
60
# include <wspiapi.h>
61
#endif
62
63
#define SOCKOPT_TYPE_ARG4 char
64
65
#else /* _WIN32 */
66
67
#include <sys/socket.h>
68
#include <netinet/in.h>
69
#include <netdb.h>
70
#define SOCKOPT_TYPE_ARG4 int
71
72
#endif /* _WIN32 */
73
74
static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
75
0
    int port) {
76
0
    char port_c[6];
77
0
    struct addrinfo *ai = NULL;
78
0
    struct addrinfo hints;
79
0
    int opt = 1;
80
0
    socket_t s;
81
0
    int rc;
82
0
    char err_msg[SSH_ERRNO_MSG_MAX] = {0};
83
84
0
    ZERO_STRUCT(hints);
85
86
0
    hints.ai_flags = AI_PASSIVE;
87
0
    hints.ai_socktype = SOCK_STREAM;
88
89
0
    snprintf(port_c, 6, "%d", port);
90
0
    rc = getaddrinfo(hostname, port_c, &hints, &ai);
91
0
    if (rc != 0) {
92
0
        ssh_set_error(sshbind,
93
0
                      SSH_FATAL,
94
0
                      "Resolving %s: %s", hostname, gai_strerror(rc));
95
0
        return -1;
96
0
    }
97
98
0
    s = socket (ai->ai_family,
99
0
                           ai->ai_socktype,
100
0
                           ai->ai_protocol);
101
0
    if (s == SSH_INVALID_SOCKET) {
102
0
        ssh_set_error(sshbind, SSH_FATAL, "%s",
103
0
                      ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
104
0
        freeaddrinfo (ai);
105
0
        return -1;
106
0
    }
107
108
0
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
109
0
                   (char *)&opt, sizeof(opt)) < 0) {
110
0
        ssh_set_error(sshbind,
111
0
                      SSH_FATAL,
112
0
                      "Setting socket options failed: %s",
113
0
                      ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
114
0
        freeaddrinfo (ai);
115
0
        CLOSE_SOCKET(s);
116
0
        return -1;
117
0
    }
118
119
0
    if (bind(s, ai->ai_addr, ai->ai_addrlen) != 0) {
120
0
        ssh_set_error(sshbind,
121
0
                      SSH_FATAL,
122
0
                      "Binding to %s:%d: %s",
123
0
                      hostname,
124
0
                      port,
125
0
                      ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
126
0
        freeaddrinfo (ai);
127
0
        CLOSE_SOCKET(s);
128
0
        return -1;
129
0
    }
130
131
0
    freeaddrinfo (ai);
132
0
    return s;
133
0
}
134
135
ssh_bind ssh_bind_new(void)
136
638
{
137
638
    ssh_bind ptr = NULL;
138
139
638
    ptr = calloc(1, sizeof(struct ssh_bind_struct));
140
638
    if (ptr == NULL) {
141
0
        return NULL;
142
0
    }
143
638
    ptr->bindfd = SSH_INVALID_SOCKET;
144
638
    ptr->bindport = 22;
145
638
    ptr->common.log_verbosity = 0;
146
147
638
    return ptr;
148
638
}
149
150
0
static int ssh_bind_import_keys(ssh_bind sshbind) {
151
0
  int rc;
152
153
0
#ifdef HAVE_ECC
154
0
  if (sshbind->ecdsa == NULL && sshbind->ecdsakey != NULL) {
155
0
      rc = ssh_pki_import_privkey_file(sshbind->ecdsakey,
156
0
                                       NULL,
157
0
                                       NULL,
158
0
                                       NULL,
159
0
                                       &sshbind->ecdsa);
160
0
      if (rc == SSH_ERROR || rc == SSH_EOF) {
161
0
          ssh_set_error(sshbind, SSH_FATAL,
162
0
                  "Failed to import private ECDSA host key");
163
0
          return SSH_ERROR;
164
0
      }
165
166
0
      if (!is_ecdsa_key_type(ssh_key_type(sshbind->ecdsa))) {
167
0
          ssh_set_error(sshbind, SSH_FATAL,
168
0
                  "The ECDSA host key has the wrong type");
169
0
          ssh_key_free(sshbind->ecdsa);
170
0
          sshbind->ecdsa = NULL;
171
0
          return SSH_ERROR;
172
0
      }
173
0
  }
174
0
#endif
175
176
0
  if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
177
0
      rc = ssh_pki_import_privkey_file(sshbind->rsakey,
178
0
                                       NULL,
179
0
                                       NULL,
180
0
                                       NULL,
181
0
                                       &sshbind->rsa);
182
0
      if (rc == SSH_ERROR || rc == SSH_EOF) {
183
0
          ssh_set_error(sshbind, SSH_FATAL,
184
0
                  "Failed to import private RSA host key");
185
0
          return SSH_ERROR;
186
0
      }
187
188
0
      if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA) {
189
0
          ssh_set_error(sshbind, SSH_FATAL,
190
0
                  "The RSA host key has the wrong type");
191
0
          ssh_key_free(sshbind->rsa);
192
0
          sshbind->rsa = NULL;
193
0
          return SSH_ERROR;
194
0
      }
195
0
  }
196
197
0
  if (sshbind->ed25519 == NULL && sshbind->ed25519key != NULL) {
198
0
      rc = ssh_pki_import_privkey_file(sshbind->ed25519key,
199
0
                                       NULL,
200
0
                                       NULL,
201
0
                                       NULL,
202
0
                                       &sshbind->ed25519);
203
0
      if (rc == SSH_ERROR || rc == SSH_EOF) {
204
0
          ssh_set_error(sshbind, SSH_FATAL,
205
0
                  "Failed to import private ED25519 host key");
206
0
          return SSH_ERROR;
207
0
      }
208
209
0
      if (ssh_key_type(sshbind->ed25519) != SSH_KEYTYPE_ED25519) {
210
0
          ssh_set_error(sshbind, SSH_FATAL,
211
0
                  "The ED25519 host key has the wrong type");
212
0
          ssh_key_free(sshbind->ed25519);
213
0
          sshbind->ed25519 = NULL;
214
0
          return SSH_ERROR;
215
0
      }
216
0
  }
217
218
0
  return SSH_OK;
219
0
}
220
221
0
int ssh_bind_listen(ssh_bind sshbind) {
222
0
    const char *host = NULL;
223
0
    socket_t fd;
224
0
    int rc;
225
226
    /* Apply global bind configurations, if it hasn't been applied before */
227
0
    rc = ssh_bind_options_parse_config(sshbind, NULL);
228
0
    if (rc != 0) {
229
0
        ssh_set_error(sshbind, SSH_FATAL,"Could not parse global config");
230
0
        return SSH_ERROR;
231
0
    }
232
233
    /* Set default hostkey paths if no hostkey was found before */
234
0
    if (sshbind->ecdsakey == NULL &&
235
0
        sshbind->rsakey == NULL &&
236
0
        sshbind->ed25519key == NULL) {
237
238
0
        sshbind->ecdsakey = strdup("/etc/ssh/ssh_host_ecdsa_key");
239
0
        sshbind->rsakey = strdup("/etc/ssh/ssh_host_rsa_key");
240
0
        sshbind->ed25519key = strdup("/etc/ssh/ssh_host_ed25519_key");
241
0
    }
242
243
    /* Apply global bind configurations, if it hasn't been applied before */
244
0
    rc = ssh_bind_options_parse_config(sshbind, NULL);
245
0
    if (rc != 0) {
246
0
        ssh_set_error(sshbind, SSH_FATAL, "Could not parse global config");
247
0
        return SSH_ERROR;
248
0
    }
249
250
    /* Set default hostkey paths if no hostkey was found before */
251
0
    if (sshbind->ecdsakey == NULL &&
252
0
        sshbind->rsakey == NULL &&
253
0
        sshbind->ed25519key == NULL) {
254
255
0
        sshbind->ecdsakey = strdup("/etc/ssh/ssh_host_ecdsa_key");
256
0
        sshbind->rsakey = strdup("/etc/ssh/ssh_host_rsa_key");
257
0
        sshbind->ed25519key = strdup("/etc/ssh/ssh_host_ed25519_key");
258
0
    }
259
260
0
    if (sshbind->rsa == NULL &&
261
0
        sshbind->ecdsa == NULL &&
262
0
        sshbind->ed25519 == NULL) {
263
0
        rc = ssh_bind_import_keys(sshbind);
264
0
        if (rc != SSH_OK) {
265
0
            return SSH_ERROR;
266
0
        }
267
0
    }
268
269
0
    if (sshbind->bindfd == SSH_INVALID_SOCKET) {
270
0
        host = sshbind->bindaddr;
271
0
        if (host == NULL) {
272
0
            host = "0.0.0.0";
273
0
        }
274
275
0
        fd = bind_socket(sshbind, host, sshbind->bindport);
276
0
        if (fd == SSH_INVALID_SOCKET) {
277
0
            return SSH_ERROR;
278
0
        }
279
280
0
        if (listen(fd, 10) < 0) {
281
0
            char err_msg[SSH_ERRNO_MSG_MAX] = {0};
282
0
            ssh_set_error(sshbind,
283
0
                          SSH_FATAL,
284
0
                          "Listening to socket %d: %s",
285
0
                          fd,
286
0
                          ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
287
0
            CLOSE_SOCKET(fd);
288
0
            return SSH_ERROR;
289
0
        }
290
291
0
        sshbind->bindfd = fd;
292
0
  } else {
293
0
      SSH_LOG(SSH_LOG_DEBUG, "Using app-provided bind socket");
294
0
  }
295
0
  return 0;
296
0
}
297
298
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks, void *userdata)
299
0
{
300
0
    if (sshbind == NULL) {
301
0
        return SSH_ERROR;
302
0
    }
303
0
    if (callbacks == NULL) {
304
0
        ssh_set_error_invalid(sshbind);
305
0
        return SSH_ERROR;
306
0
    }
307
0
    if (callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)) {
308
0
        ssh_set_error(sshbind,
309
0
                      SSH_FATAL,
310
0
                      "Invalid callback passed in (badly initialized)");
311
0
        return SSH_ERROR;
312
0
    }
313
0
    sshbind->bind_callbacks = callbacks;
314
0
    sshbind->bind_callbacks_userdata = userdata;
315
0
    return 0;
316
0
}
317
318
/** @internal
319
 * @brief callback being called by poll when an event happens
320
 *
321
 */
322
static int ssh_bind_poll_callback(ssh_poll_handle sshpoll, socket_t fd, int revents, void *user)
323
0
{
324
0
    ssh_bind sshbind = (ssh_bind)user;
325
0
    (void)sshpoll;
326
0
    (void)fd;
327
328
0
    if (revents & POLLIN) {
329
        /* new incoming connection */
330
0
        if (ssh_callbacks_exists(sshbind->bind_callbacks, incoming_connection)) {
331
0
            sshbind->bind_callbacks->incoming_connection(sshbind,
332
0
                                                         sshbind->bind_callbacks_userdata);
333
0
        }
334
0
    }
335
0
    return 0;
336
0
}
337
338
/** @internal
339
 * @brief returns the current poll handle, or creates it
340
 * @param sshbind the ssh_bind object
341
 * @returns a ssh_poll handle suitable for operation
342
 */
343
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind)
344
0
{
345
0
    short events = POLLIN;
346
347
0
    if (sshbind->poll) {
348
0
        return sshbind->poll;
349
0
    }
350
351
#ifdef POLLRDHUP
352
    events |= POLLRDHUP;
353
#endif /* POLLRDHUP */
354
355
0
    sshbind->poll = ssh_poll_new(sshbind->bindfd,
356
0
                                 events,
357
0
                                 ssh_bind_poll_callback,
358
0
                                 sshbind);
359
360
0
    return sshbind->poll;
361
0
}
362
363
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking)
364
0
{
365
0
    sshbind->blocking = blocking ? 1 : 0;
366
0
}
367
368
socket_t ssh_bind_get_fd(ssh_bind sshbind)
369
0
{
370
0
    return sshbind->bindfd;
371
0
}
372
373
void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd)
374
0
{
375
0
    sshbind->bindfd = fd;
376
0
}
377
378
void ssh_bind_fd_toaccept(ssh_bind sshbind)
379
0
{
380
0
    sshbind->toaccept = 1;
381
0
}
382
383
638
void ssh_bind_free(ssh_bind sshbind){
384
638
  int i;
385
386
638
  if (sshbind == NULL) {
387
0
    return;
388
0
  }
389
390
638
  if (sshbind->bindfd >= 0) {
391
0
      CLOSE_SOCKET(sshbind->bindfd);
392
0
  }
393
638
  sshbind->bindfd = SSH_INVALID_SOCKET;
394
395
  /* options */
396
638
  SAFE_FREE(sshbind->banner);
397
638
  SAFE_FREE(sshbind->moduli_file);
398
638
  SAFE_FREE(sshbind->bindaddr);
399
638
  SAFE_FREE(sshbind->config_dir);
400
638
  SAFE_FREE(sshbind->pubkey_accepted_key_types);
401
402
638
  SAFE_FREE(sshbind->rsakey);
403
638
  SAFE_FREE(sshbind->ecdsakey);
404
638
  SAFE_FREE(sshbind->ed25519key);
405
406
638
  ssh_key_free(sshbind->rsa);
407
638
  sshbind->rsa = NULL;
408
638
  ssh_key_free(sshbind->ecdsa);
409
638
  sshbind->ecdsa = NULL;
410
638
  ssh_key_free(sshbind->ed25519);
411
638
  sshbind->ed25519 = NULL;
412
413
7.01k
  for (i = 0; i < SSH_KEX_METHODS; i++) {
414
6.38k
    if (sshbind->wanted_methods[i]) {
415
580
      SAFE_FREE(sshbind->wanted_methods[i]);
416
580
    }
417
6.38k
  }
418
419
638
  SAFE_FREE(sshbind);
420
638
}
421
422
int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
423
0
{
424
0
    ssh_poll_handle handle = NULL;
425
0
    int i, rc;
426
427
0
    if (sshbind == NULL) {
428
0
        return SSH_ERROR;
429
0
    }
430
431
0
    if (session == NULL){
432
0
        ssh_set_error(sshbind, SSH_FATAL,"session is null");
433
0
        return SSH_ERROR;
434
0
    }
435
436
0
    session->server = 1;
437
438
    /* Copy options from bind to session */
439
0
    for (i = 0; i < SSH_KEX_METHODS; i++) {
440
0
      if (sshbind->wanted_methods[i]) {
441
0
        session->opts.wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
442
0
        if (session->opts.wanted_methods[i] == NULL) {
443
0
          return SSH_ERROR;
444
0
        }
445
0
      }
446
0
    }
447
448
0
    if (sshbind->bindaddr == NULL)
449
0
      session->opts.bindaddr = NULL;
450
0
    else {
451
0
      SAFE_FREE(session->opts.bindaddr);
452
0
      session->opts.bindaddr = strdup(sshbind->bindaddr);
453
0
      if (session->opts.bindaddr == NULL) {
454
0
        return SSH_ERROR;
455
0
      }
456
0
    }
457
458
0
    if (sshbind->pubkey_accepted_key_types != NULL) {
459
0
        if (session->opts.pubkey_accepted_types == NULL) {
460
0
            session->opts.pubkey_accepted_types = strdup(sshbind->pubkey_accepted_key_types);
461
0
            if (session->opts.pubkey_accepted_types == NULL) {
462
0
                ssh_set_error_oom(sshbind);
463
0
                return SSH_ERROR;
464
0
            }
465
0
        } else {
466
0
            char *p = NULL;
467
            /* If something was set to the session prior to calling this
468
             * function, keep only what is allowed by the options set in
469
             * sshbind */
470
0
            p = ssh_find_all_matching(sshbind->pubkey_accepted_key_types,
471
0
                                      session->opts.pubkey_accepted_types);
472
0
            if (p == NULL) {
473
0
                return SSH_ERROR;
474
0
            }
475
476
0
            SAFE_FREE(session->opts.pubkey_accepted_types);
477
0
            session->opts.pubkey_accepted_types = p;
478
0
        }
479
0
    }
480
481
0
    session->common.log_verbosity = sshbind->common.log_verbosity;
482
483
0
    if (sshbind->banner != NULL) {
484
0
        session->server_opts.custombanner = strdup(sshbind->banner);
485
0
        if (session->server_opts.custombanner == NULL) {
486
0
            ssh_set_error_oom(sshbind);
487
0
            return SSH_ERROR;
488
0
        }
489
0
    }
490
491
0
    if (sshbind->moduli_file != NULL) {
492
0
        session->server_opts.moduli_file = strdup(sshbind->moduli_file);
493
0
        if (session->server_opts.moduli_file == NULL) {
494
0
            ssh_set_error_oom(sshbind);
495
0
            return SSH_ERROR;
496
0
        }
497
0
    }
498
499
0
    session->opts.rsa_min_size = sshbind->rsa_min_size;
500
501
0
    ssh_socket_free(session->socket);
502
0
    session->socket = ssh_socket_new(session);
503
0
    if (session->socket == NULL) {
504
      /* perhaps it may be better to copy the error from session to sshbind */
505
0
      ssh_set_error_oom(sshbind);
506
0
      return SSH_ERROR;
507
0
    }
508
0
    ssh_socket_set_fd(session->socket, fd);
509
0
    handle = ssh_socket_get_poll_handle(session->socket);
510
0
    if (handle == NULL) {
511
0
        ssh_set_error_oom(sshbind);
512
0
        return SSH_ERROR;
513
0
    }
514
0
    ssh_socket_set_connected(session->socket, handle);
515
516
    /* We must try to import any keys that could be imported in case
517
     * we are not using ssh_bind_listen (which is the other place
518
     * where keys can be imported) on this ssh_bind and are instead
519
     * only using ssh_bind_accept_fd to manage sockets ourselves.
520
     */
521
0
    if (sshbind->rsa == NULL &&
522
0
        sshbind->ecdsa == NULL &&
523
0
        sshbind->ed25519 == NULL) {
524
0
        rc = ssh_bind_import_keys(sshbind);
525
0
        if (rc != SSH_OK) {
526
0
            return SSH_ERROR;
527
0
        }
528
0
    }
529
530
0
#ifdef HAVE_ECC
531
0
    if (sshbind->ecdsa) {
532
0
        session->srv.ecdsa_key = ssh_key_dup(sshbind->ecdsa);
533
0
        if (session->srv.ecdsa_key == NULL) {
534
0
          ssh_set_error_oom(sshbind);
535
0
          return SSH_ERROR;
536
0
        }
537
0
    }
538
0
#endif
539
0
    if (sshbind->rsa) {
540
0
        session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
541
0
        if (session->srv.rsa_key == NULL) {
542
0
          ssh_set_error_oom(sshbind);
543
0
          return SSH_ERROR;
544
0
        }
545
0
    }
546
0
    if (sshbind->ed25519 != NULL) {
547
0
        session->srv.ed25519_key = ssh_key_dup(sshbind->ed25519);
548
0
        if (session->srv.ed25519_key == NULL){
549
0
            ssh_set_error_oom(sshbind);
550
0
            return SSH_ERROR;
551
0
        }
552
0
    }
553
554
    /* force PRNG to change state in case we fork after ssh_bind_accept */
555
0
    ssh_reseed();
556
0
    return SSH_OK;
557
0
}
558
559
int ssh_bind_accept(ssh_bind sshbind, ssh_session session)
560
0
{
561
0
    socket_t fd = SSH_INVALID_SOCKET;
562
0
    int rc;
563
564
0
    if (sshbind->bindfd == SSH_INVALID_SOCKET) {
565
0
        ssh_set_error(sshbind, SSH_FATAL,
566
0
                      "Can't accept new clients on a not bound socket.");
567
0
        return SSH_ERROR;
568
0
    }
569
570
0
    if (session == NULL) {
571
0
        ssh_set_error(sshbind, SSH_FATAL, "session is null");
572
0
        return SSH_ERROR;
573
0
    }
574
575
0
    fd = accept(sshbind->bindfd, NULL, NULL);
576
0
    if (fd == SSH_INVALID_SOCKET) {
577
0
        char err_msg[SSH_ERRNO_MSG_MAX] = {0};
578
0
        if (errno == EINTR) {
579
0
            ssh_set_error(sshbind, SSH_EINTR,
580
0
                          "Accepting a new connection (child signal error): %s",
581
0
                          ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
582
0
        } else {
583
0
            ssh_set_error(sshbind, SSH_FATAL,
584
0
                          "Accepting a new connection: %s",
585
0
                          ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
586
0
        }
587
0
        return SSH_ERROR;
588
0
    }
589
0
    rc = ssh_bind_accept_fd(sshbind, session, fd);
590
591
0
    if (rc == SSH_ERROR) {
592
0
        CLOSE_SOCKET(fd);
593
0
        ssh_socket_free(session->socket);
594
0
    }
595
596
0
    return rc;
597
0
}
598
599
600
/**
601
 * @}
602
 */