Coverage Report

Created: 2026-04-12 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dropbear/src/svr-runopts.c
Line
Count
Source
1
/*
2
 * Dropbear - a SSH2 server
3
 * 
4
 * Copyright (c) 2002,2003 Matt Johnston
5
 * All rights reserved.
6
 * 
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 * 
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 * 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE. */
24
25
#include "includes.h"
26
#include "runopts.h"
27
#include "signkey.h"
28
#include "buffer.h"
29
#include "dbutil.h"
30
#include "algo.h"
31
#include "ecdsa.h"
32
33
#include <grp.h>
34
35
svr_runopts svr_opts; /* GLOBAL */
36
37
static void printhelp(const char * progname);
38
static void addportandaddress(const char* spec);
39
static void loadhostkey(const char *keyfile, int fatal_duplicate);
40
static void addhostkey(const char *keyfile);
41
static void load_banner();
42
43
0
static void printhelp(const char * progname) {
44
45
0
  fprintf(stderr, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
46
0
          "Usage: %s [options]\n"
47
0
          "-b bannerfile  Display the contents of bannerfile"
48
0
          " before user login\n"
49
0
          "   (default: none)\n"
50
0
          "-r keyfile      Specify hostkeys (repeatable)\n"
51
0
          "   defaults: \n"
52
0
#if DROPBEAR_DSS
53
0
          "   - dss %s\n"
54
0
#endif
55
0
#if DROPBEAR_RSA
56
0
          "   - rsa %s\n"
57
0
#endif
58
0
#if DROPBEAR_ECDSA
59
0
          "   - ecdsa %s\n"
60
0
#endif
61
0
#if DROPBEAR_ED25519
62
0
          "   - ed25519 %s\n"
63
0
#endif
64
0
#if DROPBEAR_SVR_PUBKEY_AUTH
65
0
          "-D   Directory containing authorized_keys file\n"
66
0
#endif
67
0
#if DROPBEAR_DELAY_HOSTKEY
68
0
          "-R   Create hostkeys as required\n" 
69
0
#endif
70
0
          "-F   Don't fork into background\n"
71
0
          "-e   Pass on server process environment to child process\n"
72
#ifdef DISABLE_SYSLOG
73
          "(Syslog support not compiled in, using stderr)\n"
74
#else
75
0
          "-E   Log to stderr rather than syslog\n"
76
0
#endif
77
0
#if DO_MOTD
78
0
          "-m   Don't display the motd on login\n"
79
0
#endif
80
0
          "-w   Disallow root logins\n"
81
0
#ifdef HAVE_GETGROUPLIST
82
0
          "-G   Restrict logins to members of specified group\n"
83
0
#endif
84
0
#if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
85
0
          "-s   Disable password logins\n"
86
0
          "-g   Disable password logins for root\n"
87
0
          "-B   Allow blank password logins\n"
88
0
          "-t   Enable two-factor authentication (both password and public key required)\n"
89
0
#endif
90
0
          "-T   Maximum authentication tries (default %d)\n"
91
0
#if DROPBEAR_SVR_LOCALANYFWD
92
0
          "-j   Disable local port forwarding\n"
93
0
#endif
94
0
#if DROPBEAR_SVR_REMOTETCPFWD
95
0
          "-k   Disable remote port forwarding\n"
96
0
          "-a   Allow connections to forwarded ports from any host\n"
97
0
          "-c command Force executed command\n"
98
0
#endif
99
0
          "-p [address:]port\n"
100
0
          "   Listen on specified tcp port (and optionally address),\n"
101
0
          "   up to %d can be specified\n"
102
0
          "   (default port is %s if none specified)\n"
103
0
          "-P PidFile Create pid file PidFile\n"
104
0
          "   (default %s)\n"
105
0
#ifdef SO_BINDTODEVICE
106
0
          "-l <interface>\n"
107
0
          "   interface to bind on\n"
108
0
#endif
109
0
#if INETD_MODE
110
0
          "-i   Start for inetd\n"
111
0
#endif
112
0
          "-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
113
0
          "-K <keepalive>  (0 is never, default %d, in seconds)\n"
114
0
          "-I <idle_timeout>  (0 is never, default %d, in seconds)\n"
115
0
          "-z    disable QoS\n"
116
#if DROPBEAR_PLUGIN
117
                                        "-A <authplugin>[,<options>]\n"
118
                                        "               Enable external public key auth through <authplugin>\n"
119
#endif
120
0
          "-V    Version\n"
121
#if DEBUG_TRACE
122
          "-v    verbose (repeat for more verbose)\n"
123
#endif
124
0
          ,DROPBEAR_VERSION, progname,
125
0
#if DROPBEAR_DSS
126
0
          DSS_PRIV_FILENAME,
127
0
#endif
128
0
#if DROPBEAR_RSA
129
0
          RSA_PRIV_FILENAME,
130
0
#endif
131
0
#if DROPBEAR_ECDSA
132
0
          ECDSA_PRIV_FILENAME,
133
0
#endif
134
0
#if DROPBEAR_ED25519
135
0
          ED25519_PRIV_FILENAME,
136
0
#endif
137
0
          MAX_AUTH_TRIES,
138
0
          DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
139
0
          DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
140
0
}
141
142
1
void svr_getopts(int argc, char ** argv) {
143
144
1
  unsigned int i, j;
145
1
  char ** next = NULL;
146
1
  int nextisport = 0;
147
1
  char* recv_window_arg = NULL;
148
1
  char* keepalive_arg = NULL;
149
1
  char* idle_timeout_arg = NULL;
150
1
  char* maxauthtries_arg = NULL;
151
1
  char* reexec_fd_arg = NULL;
152
1
  char* keyfile = NULL;
153
1
  char c;
154
#if DROPBEAR_PLUGIN
155
        char* pubkey_plugin = NULL;
156
#endif
157
158
159
  /* see printhelp() for options */
160
1
  svr_opts.bannerfile = NULL;
161
1
  svr_opts.banner = NULL;
162
1
  svr_opts.forced_command = NULL;
163
1
  svr_opts.forkbg = 1;
164
1
  svr_opts.norootlogin = 0;
165
1
#ifdef HAVE_GETGROUPLIST
166
1
  svr_opts.restrict_group = NULL;
167
1
  svr_opts.restrict_group_gid = 0;
168
1
#endif
169
1
  svr_opts.noauthpass = 0;
170
1
  svr_opts.norootpass = 0;
171
1
  svr_opts.allowblankpass = 0;
172
1
  svr_opts.multiauthmethod = 0;
173
1
  svr_opts.maxauthtries = MAX_AUTH_TRIES;
174
1
  svr_opts.inetdmode = 0;
175
1
  svr_opts.portcount = 0;
176
1
  svr_opts.hostkey = NULL;
177
1
  svr_opts.delay_hostkey = 0;
178
1
  svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
179
1
  svr_opts.authorized_keys_dir = "~/.ssh";
180
1
#if DROPBEAR_SVR_LOCALANYFWD
181
1
  svr_opts.nolocaltcp = 0;
182
1
#endif
183
1
#if DROPBEAR_SVR_REMOTETCPFWD
184
1
  svr_opts.noremotetcp = 0;
185
1
#endif
186
#if DROPBEAR_PLUGIN
187
        svr_opts.pubkey_plugin = NULL;
188
        svr_opts.pubkey_plugin_options = NULL;
189
#endif
190
1
  svr_opts.pass_on_env = 0;
191
1
  svr_opts.reexec_childpipe = -1;
192
193
#ifndef DISABLE_ZLIB
194
  opts.allow_compress = 1;
195
#endif 
196
197
  /* not yet
198
  opts.ipv4 = 1;
199
  opts.ipv6 = 1;
200
  */
201
1
#if DO_MOTD
202
1
  svr_opts.domotd = 1;
203
1
#endif
204
1
#ifndef DISABLE_SYSLOG
205
1
  opts.usingsyslog = 1;
206
1
#endif
207
1
  opts.recv_window = DEFAULT_RECV_WINDOW;
208
1
  opts.keepalive_secs = DEFAULT_KEEPALIVE;
209
1
  opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
210
  
211
1
#if DROPBEAR_SVR_REMOTETCPFWD
212
1
  opts.listen_fwd_all = 0;
213
1
#endif
214
1
  opts.disable_ip_tos = 0;
215
216
2
  for (i = 1; i < (unsigned int)argc; i++) {
217
1
    if (argv[i][0] != '-' || argv[i][1] == '\0')
218
0
      dropbear_exit("Invalid argument: %s", argv[i]);
219
220
2
    for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
221
1
      switch (c) {
222
0
        case 'b':
223
0
          next = &svr_opts.bannerfile;
224
0
          break;
225
0
        case 'c':
226
0
          next = &svr_opts.forced_command;
227
0
          break;
228
0
        case 'd':
229
0
        case 'r':
230
0
          next = &keyfile;
231
0
          break;
232
0
#if DROPBEAR_SVR_PUBKEY_AUTH
233
0
        case 'D':
234
0
          next = &svr_opts.authorized_keys_dir;
235
0
          break;
236
0
#endif
237
0
        case 'R':
238
0
          svr_opts.delay_hostkey = 1;
239
0
          break;
240
0
        case 'F':
241
0
          svr_opts.forkbg = 0;
242
0
          break;
243
0
#ifndef DISABLE_SYSLOG
244
1
        case 'E':
245
1
          opts.usingsyslog = 0;
246
1
          break;
247
0
#endif
248
0
        case 'e':
249
0
          svr_opts.pass_on_env = 1;
250
0
          break;
251
252
0
#if DROPBEAR_SVR_LOCALANYFWD
253
0
        case 'j':
254
0
          svr_opts.nolocaltcp = 1;
255
0
          break;
256
#else
257
        case 'j':
258
          break;
259
#endif
260
0
#if DROPBEAR_SVR_REMOTETCPFWD
261
0
        case 'k':
262
0
          svr_opts.noremotetcp = 1;
263
0
          break;
264
0
        case 'a':
265
0
          opts.listen_fwd_all = 1;
266
0
          break;
267
#else
268
        case 'k':
269
          break;
270
#endif
271
0
#if INETD_MODE
272
0
        case 'i':
273
0
          svr_opts.inetdmode = 1;
274
0
          break;
275
0
#endif
276
0
#if DROPBEAR_DO_REEXEC && NON_INETD_MODE
277
        /* For internal use by re-exec */
278
0
        case '2':
279
0
          next = &reexec_fd_arg;
280
0
          break;
281
0
#endif
282
0
        case 'p':
283
0
          nextisport = 1;
284
0
          break;
285
0
        case 'P':
286
0
          next = &svr_opts.pidfile;
287
0
          break;
288
0
#ifdef SO_BINDTODEVICE
289
0
        case 'l':
290
0
          next = &svr_opts.interface;
291
0
          break;
292
0
#endif
293
0
#if DO_MOTD
294
        /* motd is displayed by default, -m turns it off */
295
0
        case 'm':
296
0
          svr_opts.domotd = 0;
297
0
          break;
298
#else
299
        case 'm':
300
          break;
301
#endif
302
0
        case 'w':
303
0
          svr_opts.norootlogin = 1;
304
0
          break;
305
0
#ifdef HAVE_GETGROUPLIST
306
0
        case 'G':
307
0
          next = &svr_opts.restrict_group;
308
0
          break;
309
0
#endif
310
0
        case 'W':
311
0
          next = &recv_window_arg;
312
0
          break;
313
0
        case 'K':
314
0
          next = &keepalive_arg;
315
0
          break;
316
0
        case 'I':
317
0
          next = &idle_timeout_arg;
318
0
          break;
319
0
        case 'T':
320
0
          next = &maxauthtries_arg;
321
0
          break;
322
0
#if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
323
0
        case 's':
324
0
          svr_opts.noauthpass = 1;
325
0
          break;
326
0
        case 'g':
327
0
          svr_opts.norootpass = 1;
328
0
          break;
329
0
        case 'B':
330
0
          svr_opts.allowblankpass = 1;
331
0
          break;
332
0
        case 't':
333
0
          svr_opts.multiauthmethod = 1;
334
0
          break;
335
#else
336
        case 's':
337
        case 'g':
338
          break;
339
#endif
340
0
        case 'h':
341
0
          printhelp(argv[0]);
342
0
          exit(EXIT_SUCCESS);
343
0
          break;
344
0
        case 'u':
345
          /* backwards compatibility with old urandom option */
346
0
          break;
347
#if DROPBEAR_PLUGIN
348
                                case 'A':
349
                                        next = &pubkey_plugin;
350
                                        break;
351
#endif
352
#if DEBUG_TRACE
353
        case 'v':
354
          debug_trace++;
355
          break;
356
#endif
357
0
        case 'V':
358
0
          print_version();
359
0
          exit(EXIT_SUCCESS);
360
0
          break;
361
0
        case 'z':
362
0
          opts.disable_ip_tos = 1;
363
0
          break;
364
0
        default:
365
0
          fprintf(stderr, "Invalid option -%c\n", c);
366
0
          printhelp(argv[0]);
367
0
          exit(EXIT_FAILURE);
368
0
          break;
369
1
      }
370
1
    }
371
372
1
    if (!next && !nextisport)
373
1
      continue;
374
375
0
    if (c == '\0') {
376
0
      i++;
377
0
      j = 0;
378
0
      if (!argv[i]) {
379
0
        dropbear_exit("Missing argument");
380
0
      }
381
0
    }
382
383
0
    if (nextisport) {
384
0
      addportandaddress(&argv[i][j]);
385
0
      nextisport = 0;
386
0
    } else if (next) {
387
0
      *next = &argv[i][j];
388
0
      if (*next == NULL) {
389
0
        dropbear_exit("Invalid null argument");
390
0
      }
391
0
      next = NULL;
392
393
0
      if (keyfile) {
394
0
        addhostkey(keyfile);
395
0
        keyfile = NULL;
396
0
      }
397
0
    }
398
0
  }
399
400
  /* Set up listening ports */
401
1
  if (svr_opts.portcount == 0) {
402
1
    svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
403
1
    svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
404
1
    svr_opts.portcount = 1;
405
1
  }
406
407
1
  if (svr_opts.bannerfile) {
408
0
    load_banner();
409
0
  }
410
411
1
#ifdef HAVE_GETGROUPLIST
412
1
  if (svr_opts.restrict_group) {
413
0
    struct group *restrictedgroup = getgrnam(svr_opts.restrict_group);
414
415
0
    if (restrictedgroup){
416
0
      svr_opts.restrict_group_gid = restrictedgroup->gr_gid;
417
0
    } else {
418
0
      dropbear_exit("Cannot restrict logins to group '%s' as the group does not exist", svr_opts.restrict_group);
419
0
    }
420
0
  }
421
1
#endif
422
423
1
  if (recv_window_arg) {
424
0
    parse_recv_window(recv_window_arg);
425
0
  }
426
427
1
  if (maxauthtries_arg) {
428
0
    unsigned int val = 0;
429
0
    if (m_str_to_uint(maxauthtries_arg, &val) == DROPBEAR_FAILURE) {
430
0
      dropbear_exit("Bad maxauthtries '%s'", maxauthtries_arg);
431
0
    }
432
0
    svr_opts.maxauthtries = val;
433
0
  }
434
435
436
1
  if (keepalive_arg) {
437
0
    unsigned int val;
438
0
    if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
439
0
      dropbear_exit("Bad keepalive '%s'", keepalive_arg);
440
0
    }
441
0
    opts.keepalive_secs = val;
442
0
  }
443
444
1
  if (idle_timeout_arg) {
445
0
    unsigned int val;
446
0
    if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
447
0
      dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
448
0
    }
449
0
    opts.idle_timeout_secs = val;
450
0
  }
451
452
1
  if (svr_opts.forced_command) {
453
0
    dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
454
0
  }
455
456
1
  if (svr_opts.interface) {
457
0
    dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
458
0
  }
459
460
1
  if (reexec_fd_arg) {
461
0
    if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
462
0
      || svr_opts.reexec_childpipe < 0) {
463
0
      dropbear_exit("Bad -2");
464
0
    }
465
0
  }
466
467
1
  if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
468
0
    dropbear_exit("-t and -s are incompatible");
469
0
  }
470
471
1
  if (strlen(svr_opts.authorized_keys_dir) == 0) {
472
0
    dropbear_exit("Bad -D");
473
0
  }
474
475
#if DROPBEAR_PLUGIN
476
  if (pubkey_plugin) {
477
    svr_opts.pubkey_plugin = m_strdup(pubkey_plugin);
478
    char *args = strchr(svr_opts.pubkey_plugin, ',');
479
    if (args) {
480
      *args='\0';
481
      ++args;
482
    }
483
    svr_opts.pubkey_plugin_options = args;
484
  }
485
#endif
486
1
}
487
488
0
static void addportandaddress(const char* spec) {
489
0
  char *port = NULL, *address = NULL;
490
491
0
  if (svr_opts.portcount >= DROPBEAR_MAX_PORTS) {
492
0
    return;
493
0
  }
494
495
0
  if (split_address_port(spec, &address, &port) == DROPBEAR_FAILURE) {
496
0
    dropbear_exit("Bad -p argument");
497
0
  }
498
499
  /* A bare port */
500
0
  if (!port) {
501
0
    port = address;
502
0
    address = NULL;
503
0
  }
504
505
0
  if (!address) {
506
    /* no address given -> fill in the default address */
507
0
    address = m_strdup(DROPBEAR_DEFADDRESS);
508
0
  }
509
510
0
  if (port[0] == '\0') {
511
    /* empty port -> exit */
512
0
    dropbear_exit("Bad port");
513
0
  }
514
0
  svr_opts.ports[svr_opts.portcount] = port;
515
0
  svr_opts.addresses[svr_opts.portcount] = address;
516
0
  svr_opts.portcount++;
517
0
}
518
519
0
static void disablekey(enum signature_type type) {
520
0
  int i;
521
0
  TRACE(("Disabling key type %d", type))
522
0
  for (i = 0; sigalgs[i].name != NULL; i++) {
523
0
    if ((int)sigalgs[i].val == (int)type) {
524
0
      sigalgs[i].usable = 0;
525
0
      break;
526
0
    }
527
0
  }
528
0
}
529
530
969
void disable_sig_except(enum signature_type allow_type) {
531
969
  int i;
532
969
  TRACE(("Disabling other sigs except %d", allow_type));
533
9.69k
  for (i = 0; sigalgs[i].name != NULL; i++) {
534
8.72k
    enum signature_type sig_type = sigalgs[i].val;
535
8.72k
    if (sig_type != allow_type) {
536
7.75k
      sigalgs[i].usable = 0;
537
7.75k
    }
538
8.72k
  }
539
969
}
540
541
0
static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
542
0
  if (*dst) {
543
0
    if (fatal_duplicate) {
544
0
      dropbear_exit("Only one %s key can be specified", name);
545
0
    }
546
0
  } else {
547
0
    *dst = *src;
548
0
    *src = NULL;
549
0
  }
550
551
0
}
552
553
/* Must be called after syslog/etc is working */
554
0
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
555
0
  sign_key * read_key = new_sign_key();
556
0
  char *expand_path = expand_homedir_path(keyfile);
557
0
  enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
558
0
  if (readhostkey(expand_path, read_key, &type) == DROPBEAR_FAILURE) {
559
0
    if (!svr_opts.delay_hostkey) {
560
0
      dropbear_log(LOG_WARNING, "Failed loading %s", expand_path);
561
0
    }
562
0
  }
563
0
  m_free(expand_path);
564
565
0
#if DROPBEAR_RSA
566
0
  if (type == DROPBEAR_SIGNKEY_RSA) {
567
0
    loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
568
0
  }
569
0
#endif
570
571
0
#if DROPBEAR_DSS
572
0
  if (type == DROPBEAR_SIGNKEY_DSS) {
573
0
    loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
574
0
  }
575
0
#endif
576
577
0
#if DROPBEAR_ECDSA
578
0
#if DROPBEAR_ECC_256
579
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
580
0
    loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
581
0
  }
582
0
#endif
583
0
#if DROPBEAR_ECC_384
584
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
585
0
    loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
586
0
  }
587
0
#endif
588
0
#if DROPBEAR_ECC_521
589
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
590
0
    loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
591
0
  }
592
0
#endif
593
0
#endif /* DROPBEAR_ECDSA */
594
595
0
#if DROPBEAR_ED25519
596
0
  if (type == DROPBEAR_SIGNKEY_ED25519) {
597
0
    loadhostkey_helper("ed25519", (void**)&read_key->ed25519key, (void**)&svr_opts.hostkey->ed25519key, fatal_duplicate);
598
0
  }
599
0
#endif
600
601
0
  sign_key_free(read_key);
602
0
  TRACE(("leave loadhostkey"))
603
0
}
604
605
0
static void addhostkey(const char *keyfile) {
606
0
  if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
607
0
    dropbear_exit("Too many hostkeys");
608
0
  }
609
0
  svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
610
0
  svr_opts.num_hostkey_files++;
611
0
}
612
613
614
0
void load_all_hostkeys() {
615
0
  int i;
616
0
  int any_keys = 0;
617
0
#if DROPBEAR_ECDSA
618
0
  int loaded_any_ecdsa = 0;
619
0
#endif
620
621
0
  svr_opts.hostkey = new_sign_key();
622
623
0
  for (i = 0; i < svr_opts.num_hostkey_files; i++) {
624
0
    char *hostkey_file = svr_opts.hostkey_files[i];
625
0
    loadhostkey(hostkey_file, 1);
626
0
    m_free(hostkey_file);
627
0
  }
628
629
  /* Only load default host keys if a host key is not specified by the user */
630
0
  if (svr_opts.num_hostkey_files == 0) {
631
0
#if DROPBEAR_RSA
632
0
    loadhostkey(RSA_PRIV_FILENAME, 0);
633
0
#endif
634
635
0
#if DROPBEAR_DSS
636
0
    loadhostkey(DSS_PRIV_FILENAME, 0);
637
0
#endif
638
639
0
#if DROPBEAR_ECDSA
640
0
    loadhostkey(ECDSA_PRIV_FILENAME, 0);
641
0
#endif
642
0
#if DROPBEAR_ED25519
643
0
    loadhostkey(ED25519_PRIV_FILENAME, 0);
644
0
#endif
645
0
  }
646
647
0
#if DROPBEAR_RSA
648
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
649
0
#if DROPBEAR_RSA_SHA256
650
0
    disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
651
0
#endif
652
0
#if DROPBEAR_RSA_SHA1
653
0
    disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
654
0
#endif
655
0
  } else {
656
0
    any_keys = 1;
657
0
  }
658
0
#endif
659
660
0
#if DROPBEAR_DSS
661
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
662
0
    disablekey(DROPBEAR_SIGNATURE_DSS);
663
0
  } else {
664
0
    any_keys = 1;
665
0
  }
666
0
#endif
667
668
0
#if DROPBEAR_ECDSA
669
  /* We want to advertise a single ecdsa algorithm size.
670
  - If there is a ecdsa hostkey at startup we choose that that size.
671
  - If we generate at runtime we choose the default ecdsa size.
672
  - Otherwise no ecdsa keys will be advertised */
673
674
  /* check if any keys were loaded at startup */
675
0
  loaded_any_ecdsa = 
676
0
    0
677
0
#if DROPBEAR_ECC_256
678
0
    || svr_opts.hostkey->ecckey256
679
0
#endif
680
0
#if DROPBEAR_ECC_384
681
0
    || svr_opts.hostkey->ecckey384
682
0
#endif
683
0
#if DROPBEAR_ECC_521
684
0
    || svr_opts.hostkey->ecckey521
685
0
#endif
686
0
    ;
687
0
  any_keys |= loaded_any_ecdsa;
688
689
  /* Or an ecdsa key could be generated at runtime */
690
0
  any_keys |= svr_opts.delay_hostkey;
691
692
  /* At most one ecdsa key size will be left enabled */
693
0
#if DROPBEAR_ECC_256
694
0
  if (!svr_opts.hostkey->ecckey256
695
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
696
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
697
0
  }
698
0
#endif
699
0
#if DROPBEAR_ECC_384
700
0
  if (!svr_opts.hostkey->ecckey384
701
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
702
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
703
0
  }
704
0
#endif
705
0
#if DROPBEAR_ECC_521
706
0
  if (!svr_opts.hostkey->ecckey521
707
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
708
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
709
0
  }
710
0
#endif
711
0
#endif /* DROPBEAR_ECDSA */
712
713
0
#if DROPBEAR_ED25519
714
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
715
0
    disablekey(DROPBEAR_SIGNATURE_ED25519);
716
0
  } else {
717
0
    any_keys = 1;
718
0
  }
719
0
#endif
720
0
#if DROPBEAR_SK_ECDSA
721
0
  disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
722
0
#endif 
723
0
#if DROPBEAR_SK_ED25519
724
0
  disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
725
0
#endif
726
727
0
  if (!any_keys) {
728
0
    dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
729
0
  }
730
0
}
731
732
0
static void load_banner() {
733
0
  struct stat buf;
734
0
  if (stat(svr_opts.bannerfile, &buf) != 0) {
735
0
    dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
736
0
        svr_opts.bannerfile);
737
0
    return;
738
0
  }
739
740
0
  if (buf.st_size > MAX_BANNER_SIZE) {
741
0
    dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
742
0
        MAX_BANNER_SIZE);
743
0
    return;
744
0
  }
745
746
0
  svr_opts.banner = buf_new(buf.st_size);
747
0
  if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
748
0
    dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
749
0
        svr_opts.bannerfile);
750
0
    buf_free(svr_opts.banner);
751
0
    svr_opts.banner = NULL;
752
0
    return;
753
0
  }
754
0
  buf_setpos(svr_opts.banner, 0);
755
756
0
}