Coverage Report

Created: 2026-01-10 06:44

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
0
void svr_getopts(int argc, char ** argv) {
143
144
0
  unsigned int i, j;
145
0
  char ** next = NULL;
146
0
  int nextisport = 0;
147
0
  char* recv_window_arg = NULL;
148
0
  char* keepalive_arg = NULL;
149
0
  char* idle_timeout_arg = NULL;
150
0
  char* maxauthtries_arg = NULL;
151
0
  char* reexec_fd_arg = NULL;
152
0
  char* keyfile = NULL;
153
0
  char c;
154
#if DROPBEAR_PLUGIN
155
        char* pubkey_plugin = NULL;
156
#endif
157
158
159
  /* see printhelp() for options */
160
0
  svr_opts.bannerfile = NULL;
161
0
  svr_opts.banner = NULL;
162
0
  svr_opts.forced_command = NULL;
163
0
  svr_opts.forkbg = 1;
164
0
  svr_opts.norootlogin = 0;
165
0
#ifdef HAVE_GETGROUPLIST
166
0
  svr_opts.restrict_group = NULL;
167
0
  svr_opts.restrict_group_gid = 0;
168
0
#endif
169
0
  svr_opts.noauthpass = 0;
170
0
  svr_opts.norootpass = 0;
171
0
  svr_opts.allowblankpass = 0;
172
0
  svr_opts.multiauthmethod = 0;
173
0
  svr_opts.maxauthtries = MAX_AUTH_TRIES;
174
0
  svr_opts.inetdmode = 0;
175
0
  svr_opts.portcount = 0;
176
0
  svr_opts.hostkey = NULL;
177
0
  svr_opts.delay_hostkey = 0;
178
0
  svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
179
0
  svr_opts.authorized_keys_dir = "~/.ssh";
180
0
#if DROPBEAR_SVR_LOCALANYFWD
181
0
  svr_opts.nolocaltcp = 0;
182
0
#endif
183
0
#if DROPBEAR_SVR_REMOTETCPFWD
184
0
  svr_opts.noremotetcp = 0;
185
0
#endif
186
#if DROPBEAR_PLUGIN
187
        svr_opts.pubkey_plugin = NULL;
188
        svr_opts.pubkey_plugin_options = NULL;
189
#endif
190
0
  svr_opts.pass_on_env = 0;
191
0
  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
0
#if DO_MOTD
202
0
  svr_opts.domotd = 1;
203
0
#endif
204
0
#ifndef DISABLE_SYSLOG
205
0
  opts.usingsyslog = 1;
206
0
#endif
207
0
  opts.recv_window = DEFAULT_RECV_WINDOW;
208
0
  opts.keepalive_secs = DEFAULT_KEEPALIVE;
209
0
  opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
210
  
211
0
#if DROPBEAR_SVR_REMOTETCPFWD
212
0
  opts.listen_fwd_all = 0;
213
0
#endif
214
0
  opts.disable_ip_tos = 0;
215
216
0
  for (i = 1; i < (unsigned int)argc; i++) {
217
0
    if (argv[i][0] != '-' || argv[i][1] == '\0')
218
0
      dropbear_exit("Invalid argument: %s", argv[i]);
219
220
0
    for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
221
0
      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
0
        case 'E':
245
0
          opts.usingsyslog = 0;
246
0
          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
0
      }
370
0
    }
371
372
0
    if (!next && !nextisport)
373
0
      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
0
  if (svr_opts.portcount == 0) {
402
0
    svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
403
0
    svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
404
0
    svr_opts.portcount = 1;
405
0
  }
406
407
0
  if (svr_opts.bannerfile) {
408
0
    load_banner();
409
0
  }
410
411
0
#ifdef HAVE_GETGROUPLIST
412
0
  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
0
#endif
422
423
0
  if (recv_window_arg) {
424
0
    parse_recv_window(recv_window_arg);
425
0
  }
426
427
0
  if (maxauthtries_arg) {
428
0
    unsigned int val = 0;
429
0
    if (m_str_to_uint(maxauthtries_arg, &val) == DROPBEAR_FAILURE 
430
0
      || val == 0) {
431
0
      dropbear_exit("Bad maxauthtries '%s'", maxauthtries_arg);
432
0
    }
433
0
    svr_opts.maxauthtries = val;
434
0
  }
435
436
437
0
  if (keepalive_arg) {
438
0
    unsigned int val;
439
0
    if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
440
0
      dropbear_exit("Bad keepalive '%s'", keepalive_arg);
441
0
    }
442
0
    opts.keepalive_secs = val;
443
0
  }
444
445
0
  if (idle_timeout_arg) {
446
0
    unsigned int val;
447
0
    if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
448
0
      dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
449
0
    }
450
0
    opts.idle_timeout_secs = val;
451
0
  }
452
453
0
  if (svr_opts.forced_command) {
454
0
    dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
455
0
  }
456
457
0
  if (svr_opts.interface) {
458
0
    dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
459
0
  }
460
461
0
  if (reexec_fd_arg) {
462
0
    if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
463
0
      || svr_opts.reexec_childpipe < 0) {
464
0
      dropbear_exit("Bad -2");
465
0
    }
466
0
  }
467
468
0
  if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
469
0
    dropbear_exit("-t and -s are incompatible");
470
0
  }
471
472
0
  if (strlen(svr_opts.authorized_keys_dir) == 0) {
473
0
    dropbear_exit("Bad -D");
474
0
  }
475
476
#if DROPBEAR_PLUGIN
477
  if (pubkey_plugin) {
478
    svr_opts.pubkey_plugin = m_strdup(pubkey_plugin);
479
    char *args = strchr(svr_opts.pubkey_plugin, ',');
480
    if (args) {
481
      *args='\0';
482
      ++args;
483
    }
484
    svr_opts.pubkey_plugin_options = args;
485
  }
486
#endif
487
0
}
488
489
0
static void addportandaddress(const char* spec) {
490
0
  char *port = NULL, *address = NULL;
491
492
0
  if (svr_opts.portcount >= DROPBEAR_MAX_PORTS) {
493
0
    return;
494
0
  }
495
496
0
  if (split_address_port(spec, &address, &port) == DROPBEAR_FAILURE) {
497
0
    dropbear_exit("Bad -p argument");
498
0
  }
499
500
  /* A bare port */
501
0
  if (!port) {
502
0
    port = address;
503
0
    address = NULL;
504
0
  }
505
506
0
  if (!address) {
507
    /* no address given -> fill in the default address */
508
0
    address = m_strdup(DROPBEAR_DEFADDRESS);
509
0
  }
510
511
0
  if (port[0] == '\0') {
512
    /* empty port -> exit */
513
0
    dropbear_exit("Bad port");
514
0
  }
515
0
  svr_opts.ports[svr_opts.portcount] = port;
516
0
  svr_opts.addresses[svr_opts.portcount] = address;
517
0
  svr_opts.portcount++;
518
0
}
519
520
0
static void disablekey(enum signature_type type) {
521
0
  int i;
522
0
  TRACE(("Disabling key type %d", type))
523
0
  for (i = 0; sigalgs[i].name != NULL; i++) {
524
0
    if ((int)sigalgs[i].val == (int)type) {
525
0
      sigalgs[i].usable = 0;
526
0
      break;
527
0
    }
528
0
  }
529
0
}
530
531
0
void disable_sig_except(enum signature_type allow_type) {
532
0
  int i;
533
0
  TRACE(("Disabling other sigs except %d", allow_type));
534
0
  for (i = 0; sigalgs[i].name != NULL; i++) {
535
0
    enum signature_type sig_type = sigalgs[i].val;
536
0
    if (sig_type != allow_type) {
537
0
      sigalgs[i].usable = 0;
538
0
    }
539
0
  }
540
0
}
541
542
0
static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
543
0
  if (*dst) {
544
0
    if (fatal_duplicate) {
545
0
      dropbear_exit("Only one %s key can be specified", name);
546
0
    }
547
0
  } else {
548
0
    *dst = *src;
549
0
    *src = NULL;
550
0
  }
551
552
0
}
553
554
/* Must be called after syslog/etc is working */
555
0
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
556
0
  sign_key * read_key = new_sign_key();
557
0
  char *expand_path = expand_homedir_path(keyfile);
558
0
  enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
559
0
  if (readhostkey(expand_path, read_key, &type) == DROPBEAR_FAILURE) {
560
0
    if (!svr_opts.delay_hostkey) {
561
0
      dropbear_log(LOG_WARNING, "Failed loading %s", expand_path);
562
0
    }
563
0
  }
564
0
  m_free(expand_path);
565
566
0
#if DROPBEAR_RSA
567
0
  if (type == DROPBEAR_SIGNKEY_RSA) {
568
0
    loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
569
0
  }
570
0
#endif
571
572
0
#if DROPBEAR_DSS
573
0
  if (type == DROPBEAR_SIGNKEY_DSS) {
574
0
    loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
575
0
  }
576
0
#endif
577
578
0
#if DROPBEAR_ECDSA
579
0
#if DROPBEAR_ECC_256
580
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
581
0
    loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
582
0
  }
583
0
#endif
584
0
#if DROPBEAR_ECC_384
585
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
586
0
    loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
587
0
  }
588
0
#endif
589
0
#if DROPBEAR_ECC_521
590
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
591
0
    loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
592
0
  }
593
0
#endif
594
0
#endif /* DROPBEAR_ECDSA */
595
596
0
#if DROPBEAR_ED25519
597
0
  if (type == DROPBEAR_SIGNKEY_ED25519) {
598
0
    loadhostkey_helper("ed25519", (void**)&read_key->ed25519key, (void**)&svr_opts.hostkey->ed25519key, fatal_duplicate);
599
0
  }
600
0
#endif
601
602
0
  sign_key_free(read_key);
603
0
  TRACE(("leave loadhostkey"))
604
0
}
605
606
0
static void addhostkey(const char *keyfile) {
607
0
  if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
608
0
    dropbear_exit("Too many hostkeys");
609
0
  }
610
0
  svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
611
0
  svr_opts.num_hostkey_files++;
612
0
}
613
614
615
0
void load_all_hostkeys() {
616
0
  int i;
617
0
  int any_keys = 0;
618
0
#if DROPBEAR_ECDSA
619
0
  int loaded_any_ecdsa = 0;
620
0
#endif
621
622
0
  svr_opts.hostkey = new_sign_key();
623
624
0
  for (i = 0; i < svr_opts.num_hostkey_files; i++) {
625
0
    char *hostkey_file = svr_opts.hostkey_files[i];
626
0
    loadhostkey(hostkey_file, 1);
627
0
    m_free(hostkey_file);
628
0
  }
629
630
  /* Only load default host keys if a host key is not specified by the user */
631
0
  if (svr_opts.num_hostkey_files == 0) {
632
0
#if DROPBEAR_RSA
633
0
    loadhostkey(RSA_PRIV_FILENAME, 0);
634
0
#endif
635
636
0
#if DROPBEAR_DSS
637
0
    loadhostkey(DSS_PRIV_FILENAME, 0);
638
0
#endif
639
640
0
#if DROPBEAR_ECDSA
641
0
    loadhostkey(ECDSA_PRIV_FILENAME, 0);
642
0
#endif
643
0
#if DROPBEAR_ED25519
644
0
    loadhostkey(ED25519_PRIV_FILENAME, 0);
645
0
#endif
646
0
  }
647
648
0
#if DROPBEAR_RSA
649
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
650
0
#if DROPBEAR_RSA_SHA256
651
0
    disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
652
0
#endif
653
0
#if DROPBEAR_RSA_SHA1
654
0
    disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
655
0
#endif
656
0
  } else {
657
0
    any_keys = 1;
658
0
  }
659
0
#endif
660
661
0
#if DROPBEAR_DSS
662
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
663
0
    disablekey(DROPBEAR_SIGNATURE_DSS);
664
0
  } else {
665
0
    any_keys = 1;
666
0
  }
667
0
#endif
668
669
0
#if DROPBEAR_ECDSA
670
  /* We want to advertise a single ecdsa algorithm size.
671
  - If there is a ecdsa hostkey at startup we choose that that size.
672
  - If we generate at runtime we choose the default ecdsa size.
673
  - Otherwise no ecdsa keys will be advertised */
674
675
  /* check if any keys were loaded at startup */
676
0
  loaded_any_ecdsa = 
677
0
    0
678
0
#if DROPBEAR_ECC_256
679
0
    || svr_opts.hostkey->ecckey256
680
0
#endif
681
0
#if DROPBEAR_ECC_384
682
0
    || svr_opts.hostkey->ecckey384
683
0
#endif
684
0
#if DROPBEAR_ECC_521
685
0
    || svr_opts.hostkey->ecckey521
686
0
#endif
687
0
    ;
688
0
  any_keys |= loaded_any_ecdsa;
689
690
  /* Or an ecdsa key could be generated at runtime */
691
0
  any_keys |= svr_opts.delay_hostkey;
692
693
  /* At most one ecdsa key size will be left enabled */
694
0
#if DROPBEAR_ECC_256
695
0
  if (!svr_opts.hostkey->ecckey256
696
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
697
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
698
0
  }
699
0
#endif
700
0
#if DROPBEAR_ECC_384
701
0
  if (!svr_opts.hostkey->ecckey384
702
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
703
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
704
0
  }
705
0
#endif
706
0
#if DROPBEAR_ECC_521
707
0
  if (!svr_opts.hostkey->ecckey521
708
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
709
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
710
0
  }
711
0
#endif
712
0
#endif /* DROPBEAR_ECDSA */
713
714
0
#if DROPBEAR_ED25519
715
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
716
0
    disablekey(DROPBEAR_SIGNATURE_ED25519);
717
0
  } else {
718
0
    any_keys = 1;
719
0
  }
720
0
#endif
721
0
#if DROPBEAR_SK_ECDSA
722
0
  disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
723
0
#endif 
724
0
#if DROPBEAR_SK_ED25519
725
0
  disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
726
0
#endif
727
728
0
  if (!any_keys) {
729
0
    dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
730
0
  }
731
0
}
732
733
0
static void load_banner() {
734
0
  struct stat buf;
735
0
  if (stat(svr_opts.bannerfile, &buf) != 0) {
736
0
    dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
737
0
        svr_opts.bannerfile);
738
0
    return;
739
0
  }
740
741
0
  if (buf.st_size > MAX_BANNER_SIZE) {
742
0
    dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
743
0
        MAX_BANNER_SIZE);
744
0
    return;
745
0
  }
746
747
0
  svr_opts.banner = buf_new(buf.st_size);
748
0
  if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
749
0
    dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
750
0
        svr_opts.bannerfile);
751
0
    buf_free(svr_opts.banner);
752
0
    svr_opts.banner = NULL;
753
0
    return;
754
0
  }
755
0
  buf_setpos(svr_opts.banner, 0);
756
757
0
}