Coverage Report

Created: 2026-07-15 06:43

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(void);
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
#if DEPRECATED_TWO_FACTOR
89
          "-t   Enable two-factor authentication (both password and public key required)\n"
90
#endif
91
0
#endif
92
0
          "-T   Maximum authentication tries (default %d)\n"
93
0
#if DROPBEAR_SVR_LOCALANYFWD
94
0
          "-j   Disable local port/stream forwarding\n"
95
0
#endif
96
0
#if DROPBEAR_SVR_REMOTEANYFWD
97
0
          "-k   Disable remote port/stream forwarding\n"
98
0
#endif
99
0
#if DROPBEAR_SVR_REMOTETCPFWD
100
0
          "-a   Allow connections to forwarded ports from any host\n"
101
0
#endif
102
0
          "-c command Force executed command\n"
103
0
          "-p [address:]port\n"
104
0
          "   Listen on specified tcp port (and optionally address),\n"
105
0
          "   up to %d can be specified\n"
106
0
          "   (default port is %s if none specified)\n"
107
0
          "-P PidFile Create pid file PidFile\n"
108
0
          "   (default %s)\n"
109
0
#ifdef SO_BINDTODEVICE
110
0
          "-l <interface>\n"
111
0
          "   interface to bind on\n"
112
0
#endif
113
0
#if INETD_MODE
114
0
          "-i   Start for inetd\n"
115
0
#endif
116
0
          "-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
117
0
          "-K <keepalive>  (0 is never, default %d, in seconds)\n"
118
0
          "-I <idle_timeout>  (0 is never, default %d, in seconds)\n"
119
0
          "-M <max_duration>  (0 is off, default %d, in seconds)\n"
120
0
          "-z    disable QoS\n"
121
#if DROPBEAR_PLUGIN
122
                                        "-A <authplugin>[,<options>]\n"
123
                                        "               Enable external public key auth through <authplugin>\n"
124
#endif
125
0
          "-Q    <algo>   Print supported algorithms, or -Q help\n"
126
0
          "-V    Version\n"
127
#if DEBUG_TRACE
128
          "-v    verbose (repeat for more verbose)\n"
129
#endif
130
0
          ,DROPBEAR_VERSION, progname,
131
0
#if DROPBEAR_DSS
132
0
          DSS_PRIV_FILENAME,
133
0
#endif
134
0
#if DROPBEAR_RSA
135
0
          RSA_PRIV_FILENAME,
136
0
#endif
137
0
#if DROPBEAR_ECDSA
138
0
          ECDSA_PRIV_FILENAME,
139
0
#endif
140
0
#if DROPBEAR_ED25519
141
0
          ED25519_PRIV_FILENAME,
142
0
#endif
143
0
          MAX_AUTH_TRIES,
144
0
          DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
145
0
          DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT,
146
0
          DEFAULT_MAX_DURATION);
147
0
}
148
149
1
void svr_getopts(int argc, char ** argv) {
150
151
1
  unsigned int i, j;
152
1
  char ** next = NULL;
153
1
  int nextisport = 0;
154
1
  char* recv_window_arg = NULL;
155
1
  char* keepalive_arg = NULL;
156
1
  char* idle_timeout_arg = NULL;
157
1
  char* max_duration_arg = NULL;
158
1
  char* maxauthtries_arg = NULL;
159
1
  char* reexec_fd_arg = NULL;
160
1
  char* keyfile = NULL;
161
1
  char *algo_print_arg = NULL;
162
1
  char c;
163
#if DROPBEAR_PLUGIN
164
        char* pubkey_plugin = NULL;
165
#endif
166
167
168
  /* see printhelp() for options */
169
1
  svr_opts.bannerfile = NULL;
170
1
  svr_opts.banner = NULL;
171
1
  svr_opts.forced_command = NULL;
172
1
  svr_opts.forkbg = 1;
173
1
  svr_opts.norootlogin = 0;
174
1
#ifdef HAVE_GETGROUPLIST
175
1
  svr_opts.restrict_group = NULL;
176
1
  svr_opts.restrict_group_gid = 0;
177
1
#endif
178
1
  svr_opts.noauthpass = 0;
179
1
  svr_opts.norootpass = 0;
180
1
  svr_opts.allowblankpass = 0;
181
1
  svr_opts.multiauthmethod = 0;
182
1
  svr_opts.maxauthtries = MAX_AUTH_TRIES;
183
1
  svr_opts.inetdmode = 0;
184
1
  svr_opts.portcount = 0;
185
1
  svr_opts.hostkey = NULL;
186
1
  svr_opts.delay_hostkey = 0;
187
1
  svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
188
1
  svr_opts.authorized_keys_dir = "~/.ssh";
189
1
#if DROPBEAR_SVR_LOCALANYFWD
190
1
  svr_opts.nolocaltcp = 0;
191
1
#endif
192
1
#if DROPBEAR_SVR_REMOTEANYFWD
193
1
  svr_opts.noremotefwd = 0;
194
1
#endif
195
#if DROPBEAR_PLUGIN
196
        svr_opts.pubkey_plugin = NULL;
197
        svr_opts.pubkey_plugin_options = NULL;
198
#endif
199
1
  svr_opts.pass_on_env = 0;
200
1
  svr_opts.reexec_childpipe = -1;
201
202
#ifndef DISABLE_ZLIB
203
  opts.compression = 1;
204
#endif 
205
206
  /* not yet
207
  opts.ipv4 = 1;
208
  opts.ipv6 = 1;
209
  */
210
1
#if DO_MOTD
211
1
  svr_opts.domotd = 1;
212
1
#endif
213
1
#ifndef DISABLE_SYSLOG
214
1
  opts.usingsyslog = 1;
215
1
#endif
216
1
  opts.recv_window = DEFAULT_RECV_WINDOW;
217
1
  opts.keepalive_secs = DEFAULT_KEEPALIVE;
218
1
  opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
219
1
  opts.max_duration_secs = DEFAULT_MAX_DURATION;
220
221
1
#if DROPBEAR_SVR_REMOTETCPFWD
222
1
  opts.listen_fwd_all = 0;
223
1
#endif
224
1
  opts.disable_ip_tos = 0;
225
226
2
  for (i = 1; i < (unsigned int)argc; i++) {
227
1
    if (argv[i][0] != '-' || argv[i][1] == '\0')
228
0
      dropbear_exit("Invalid argument: %s", argv[i]);
229
230
2
    for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
231
1
      switch (c) {
232
0
        case 'b':
233
0
          next = &svr_opts.bannerfile;
234
0
          break;
235
0
        case 'c':
236
0
          next = &svr_opts.forced_command;
237
0
          break;
238
0
        case 'd':
239
0
        case 'r':
240
0
          next = &keyfile;
241
0
          break;
242
0
#if DROPBEAR_SVR_PUBKEY_AUTH
243
0
        case 'D':
244
0
          next = &svr_opts.authorized_keys_dir;
245
0
          break;
246
0
#endif
247
0
        case 'R':
248
0
          svr_opts.delay_hostkey = 1;
249
0
          break;
250
0
        case 'F':
251
0
          svr_opts.forkbg = 0;
252
0
          break;
253
0
#ifndef DISABLE_SYSLOG
254
1
        case 'E':
255
1
          opts.usingsyslog = 0;
256
1
          break;
257
0
#endif
258
0
        case 'e':
259
0
          svr_opts.pass_on_env = 1;
260
0
          break;
261
262
0
#if DROPBEAR_SVR_LOCALANYFWD
263
0
        case 'j':
264
0
          svr_opts.nolocaltcp = 1;
265
0
          break;
266
#else
267
        case 'j':
268
          /* Ignore the flag */
269
          break;
270
#endif
271
0
#if DROPBEAR_SVR_REMOTEANYFWD
272
0
        case 'k':
273
0
          svr_opts.noremotefwd = 1;
274
0
          break;
275
#else
276
        case 'k':
277
          /* Ignore the flag */
278
          break;
279
#endif
280
0
#if DROPBEAR_SVR_REMOTETCPFWD
281
0
        case 'a':
282
0
          opts.listen_fwd_all = 1;
283
0
          break;
284
0
#endif
285
0
#if INETD_MODE
286
0
        case 'i':
287
0
          svr_opts.inetdmode = 1;
288
0
          break;
289
0
#endif
290
0
#if DROPBEAR_DO_REEXEC && NON_INETD_MODE
291
        /* For internal use by re-exec */
292
0
        case '2':
293
0
          next = &reexec_fd_arg;
294
0
          break;
295
0
#endif
296
0
        case 'p':
297
0
          nextisport = 1;
298
0
          break;
299
0
        case 'P':
300
0
          next = &svr_opts.pidfile;
301
0
          break;
302
0
#ifdef SO_BINDTODEVICE
303
0
        case 'l':
304
0
          next = &svr_opts.interface;
305
0
          break;
306
0
#endif
307
0
#if DO_MOTD
308
        /* motd is displayed by default, -m turns it off */
309
0
        case 'm':
310
0
          svr_opts.domotd = 0;
311
0
          break;
312
#else
313
        case 'm':
314
          break;
315
#endif
316
0
        case 'w':
317
0
          svr_opts.norootlogin = 1;
318
0
          break;
319
0
#ifdef HAVE_GETGROUPLIST
320
0
        case 'G':
321
0
          next = &svr_opts.restrict_group;
322
0
          break;
323
0
#endif
324
0
        case 'W':
325
0
          next = &recv_window_arg;
326
0
          break;
327
0
        case 'K':
328
0
          next = &keepalive_arg;
329
0
          break;
330
0
        case 'I':
331
0
          next = &idle_timeout_arg;
332
0
          break;
333
0
        case 'M':
334
0
          next = &max_duration_arg;
335
0
          break;
336
0
        case 'T':
337
0
          next = &maxauthtries_arg;
338
0
          break;
339
0
#if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
340
0
        case 's':
341
0
          svr_opts.noauthpass = 1;
342
0
          break;
343
0
        case 'g':
344
0
          svr_opts.norootpass = 1;
345
0
          break;
346
0
        case 'B':
347
0
          svr_opts.allowblankpass = 1;
348
0
          break;
349
#if DEPRECATED_TWO_FACTOR
350
        case 't':
351
          svr_opts.multiauthmethod = 1;
352
          break;
353
#endif
354
#else
355
        case 's':
356
        case 'g':
357
          break;
358
#endif
359
0
        case 'Q':
360
0
          next = &algo_print_arg;
361
0
          break;
362
0
        case 'h':
363
0
          printhelp(argv[0]);
364
0
          exit(EXIT_SUCCESS);
365
0
          break;
366
0
        case 'u':
367
          /* backwards compatibility with old urandom option */
368
0
          break;
369
#if DROPBEAR_PLUGIN
370
                                case 'A':
371
                                        next = &pubkey_plugin;
372
                                        break;
373
#endif
374
#if DEBUG_TRACE
375
        case 'v':
376
          debug_trace++;
377
          break;
378
#endif
379
0
        case 'V':
380
0
          print_version();
381
0
          exit(EXIT_SUCCESS);
382
0
          break;
383
0
        case 'z':
384
0
          opts.disable_ip_tos = 1;
385
0
          break;
386
0
        default:
387
0
          fprintf(stderr, "Invalid option -%c\n", c);
388
0
          printhelp(argv[0]);
389
0
          exit(EXIT_FAILURE);
390
0
          break;
391
1
      }
392
1
    }
393
394
1
    if (!next && !nextisport)
395
1
      continue;
396
397
0
    if (c == '\0') {
398
0
      i++;
399
0
      j = 0;
400
0
      if (!argv[i]) {
401
0
        dropbear_exit("Missing argument");
402
0
      }
403
0
    }
404
405
0
    if (nextisport) {
406
0
      addportandaddress(&argv[i][j]);
407
0
      nextisport = 0;
408
0
    } else if (next) {
409
0
      *next = &argv[i][j];
410
0
      if (*next == NULL) {
411
0
        dropbear_exit("Invalid null argument");
412
0
      }
413
0
      next = NULL;
414
415
0
      if (keyfile) {
416
0
        addhostkey(keyfile);
417
0
        keyfile = NULL;
418
0
      }
419
0
    }
420
0
  }
421
422
  /* Set up listening ports */
423
1
  if (svr_opts.portcount == 0) {
424
1
    svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
425
1
    svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
426
1
    svr_opts.portcount = 1;
427
1
  }
428
429
1
  if (svr_opts.bannerfile) {
430
0
    load_banner();
431
0
  }
432
433
1
#ifdef HAVE_GETGROUPLIST
434
1
  if (svr_opts.restrict_group) {
435
0
    struct group *restrictedgroup = getgrnam(svr_opts.restrict_group);
436
437
0
    if (restrictedgroup){
438
0
      svr_opts.restrict_group_gid = restrictedgroup->gr_gid;
439
0
    } else {
440
0
      dropbear_exit("Cannot restrict logins to group '%s' as the group does not exist", svr_opts.restrict_group);
441
0
    }
442
0
  }
443
1
#endif
444
445
1
  if (recv_window_arg) {
446
0
    parse_recv_window(recv_window_arg);
447
0
  }
448
449
1
  if (maxauthtries_arg) {
450
0
    unsigned int val = 0;
451
0
    if (m_str_to_uint(maxauthtries_arg, &val) == DROPBEAR_FAILURE) {
452
0
      dropbear_exit("Bad maxauthtries '%s'", maxauthtries_arg);
453
0
    }
454
0
    svr_opts.maxauthtries = val;
455
0
  }
456
457
458
1
  if (keepalive_arg) {
459
0
    unsigned int val;
460
0
    if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
461
0
      dropbear_exit("Bad keepalive '%s'", keepalive_arg);
462
0
    }
463
0
    opts.keepalive_secs = val;
464
0
  }
465
466
1
  if (idle_timeout_arg) {
467
0
    unsigned int val;
468
0
    if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
469
0
      dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
470
0
    }
471
0
    opts.idle_timeout_secs = val;
472
0
  }
473
474
1
  if (max_duration_arg) {
475
0
    unsigned int val;
476
0
    if (m_str_to_uint(max_duration_arg, &val) == DROPBEAR_FAILURE) {
477
0
      dropbear_exit("Bad max_duration '%s'", max_duration_arg);
478
0
    }
479
0
    opts.max_duration_secs = val;
480
0
  }
481
482
1
  if (svr_opts.forced_command) {
483
0
    dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
484
0
  }
485
486
1
  if (svr_opts.interface) {
487
0
    dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
488
0
  }
489
490
1
  if (reexec_fd_arg) {
491
0
    if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
492
0
      || svr_opts.reexec_childpipe < 0) {
493
0
      dropbear_exit("Bad -2");
494
0
    }
495
0
  }
496
497
1
  if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
498
0
    dropbear_exit("-t and -s are incompatible");
499
0
  }
500
1
  if (svr_opts.multiauthmethod && svr_opts.allowblankpass) {
501
0
    dropbear_exit("-t and -B are incompatible");
502
0
  }
503
504
1
  if (strlen(svr_opts.authorized_keys_dir) == 0) {
505
0
    dropbear_exit("Bad -D");
506
0
  }
507
508
#if DROPBEAR_PLUGIN
509
  if (pubkey_plugin) {
510
    if (svr_opts.multiauthmethod) {
511
      dropbear_exit("-t and plugins are incompatible");
512
    }
513
514
    svr_opts.pubkey_plugin = m_strdup(pubkey_plugin);
515
    char *args = strchr(svr_opts.pubkey_plugin, ',');
516
    if (args) {
517
      *args='\0';
518
      ++args;
519
    }
520
    svr_opts.pubkey_plugin_options = args;
521
  }
522
#endif
523
1
  if (algo_print_arg) {
524
0
    print_algos(algo_print_arg);
525
    /* No return */
526
0
  }
527
1
}
528
529
0
static void addportandaddress(const char* spec) {
530
0
  char *port = NULL, *address = NULL;
531
532
0
  if (svr_opts.portcount >= DROPBEAR_MAX_PORTS) {
533
0
    return;
534
0
  }
535
536
0
  if (split_address_port(spec, &address, &port) == DROPBEAR_FAILURE) {
537
0
    dropbear_exit("Bad -p argument");
538
0
  }
539
540
  /* A bare port */
541
0
  if (!port) {
542
0
    port = address;
543
0
    address = NULL;
544
0
  }
545
546
0
  if (!address) {
547
    /* no address given -> fill in the default address */
548
0
    address = m_strdup(DROPBEAR_DEFADDRESS);
549
0
  }
550
551
0
  if (port[0] == '\0') {
552
    /* empty port -> exit */
553
0
    dropbear_exit("Bad port");
554
0
  }
555
0
  svr_opts.ports[svr_opts.portcount] = port;
556
0
  svr_opts.addresses[svr_opts.portcount] = address;
557
0
  svr_opts.portcount++;
558
0
}
559
560
0
static void disablekey(enum signature_type type) {
561
0
  int i;
562
0
  TRACE(("Disabling key type %d", type))
563
0
  for (i = 0; sigalgs[i].name != NULL; i++) {
564
0
    if ((int)sigalgs[i].val == (int)type) {
565
0
      sigalgs[i].usable = 0;
566
0
      break;
567
0
    }
568
0
  }
569
0
}
570
571
1.75k
void disable_sig_except(enum signature_type allow_type) {
572
1.75k
  int i;
573
1.75k
  TRACE(("Disabling other sigs except %d", allow_type));
574
17.5k
  for (i = 0; sigalgs[i].name != NULL; i++) {
575
15.8k
    enum signature_type sig_type = sigalgs[i].val;
576
15.8k
    if (sig_type != allow_type) {
577
14.0k
      sigalgs[i].usable = 0;
578
14.0k
    }
579
15.8k
  }
580
1.75k
}
581
582
0
static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
583
0
  if (*dst) {
584
0
    if (fatal_duplicate) {
585
0
      dropbear_exit("Only one %s key can be specified", name);
586
0
    }
587
0
  } else {
588
0
    *dst = *src;
589
0
    *src = NULL;
590
0
  }
591
592
0
}
593
594
/* Must be called after syslog/etc is working */
595
0
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
596
0
  sign_key * read_key = new_sign_key();
597
0
  char *expand_path = expand_homedir_path(keyfile);
598
0
  enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
599
0
  if (readhostkey(expand_path, read_key, &type) == DROPBEAR_FAILURE) {
600
0
    if (!svr_opts.delay_hostkey) {
601
0
      dropbear_log(LOG_WARNING, "Failed loading %s", expand_path);
602
0
    }
603
0
  }
604
0
  m_free(expand_path);
605
606
0
#if DROPBEAR_RSA
607
0
  if (type == DROPBEAR_SIGNKEY_RSA) {
608
0
    loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
609
0
  }
610
0
#endif
611
612
0
#if DROPBEAR_DSS
613
0
  if (type == DROPBEAR_SIGNKEY_DSS) {
614
0
    loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
615
0
  }
616
0
#endif
617
618
0
#if DROPBEAR_ECDSA
619
0
#if DROPBEAR_ECC_256
620
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
621
0
    loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
622
0
  }
623
0
#endif
624
0
#if DROPBEAR_ECC_384
625
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
626
0
    loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
627
0
  }
628
0
#endif
629
0
#if DROPBEAR_ECC_521
630
0
  if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
631
0
    loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
632
0
  }
633
0
#endif
634
0
#endif /* DROPBEAR_ECDSA */
635
636
0
#if DROPBEAR_ED25519
637
0
  if (type == DROPBEAR_SIGNKEY_ED25519) {
638
0
    loadhostkey_helper("ed25519", (void**)&read_key->ed25519key, (void**)&svr_opts.hostkey->ed25519key, fatal_duplicate);
639
0
  }
640
0
#endif
641
642
0
  sign_key_free(read_key);
643
0
  TRACE(("leave loadhostkey"))
644
0
}
645
646
0
static void addhostkey(const char *keyfile) {
647
0
  if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
648
0
    dropbear_exit("Too many hostkeys");
649
0
  }
650
0
  svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
651
0
  svr_opts.num_hostkey_files++;
652
0
}
653
654
655
0
void load_all_hostkeys() {
656
0
  int i;
657
0
  int any_keys = 0;
658
0
#if DROPBEAR_ECDSA
659
0
  int loaded_any_ecdsa = 0;
660
0
#endif
661
662
0
  svr_opts.hostkey = new_sign_key();
663
664
0
  for (i = 0; i < svr_opts.num_hostkey_files; i++) {
665
0
    char *hostkey_file = svr_opts.hostkey_files[i];
666
0
    loadhostkey(hostkey_file, 1);
667
0
    m_free(hostkey_file);
668
0
  }
669
670
  /* Only load default host keys if a host key is not specified by the user */
671
0
  if (svr_opts.num_hostkey_files == 0) {
672
0
#if DROPBEAR_RSA
673
0
    loadhostkey(RSA_PRIV_FILENAME, 0);
674
0
#endif
675
676
0
#if DROPBEAR_DSS
677
0
    loadhostkey(DSS_PRIV_FILENAME, 0);
678
0
#endif
679
680
0
#if DROPBEAR_ECDSA
681
0
    loadhostkey(ECDSA_PRIV_FILENAME, 0);
682
0
#endif
683
0
#if DROPBEAR_ED25519
684
0
    loadhostkey(ED25519_PRIV_FILENAME, 0);
685
0
#endif
686
0
  }
687
688
0
#if DROPBEAR_RSA
689
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
690
0
#if DROPBEAR_RSA_SHA256
691
0
    disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
692
0
#endif
693
0
#if DROPBEAR_RSA_SHA1
694
0
    disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
695
0
#endif
696
0
  } else {
697
0
    any_keys = 1;
698
0
  }
699
0
#endif
700
701
0
#if DROPBEAR_DSS
702
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
703
0
    disablekey(DROPBEAR_SIGNATURE_DSS);
704
0
  } else {
705
0
    any_keys = 1;
706
0
  }
707
0
#endif
708
709
0
#if DROPBEAR_ECDSA
710
  /* We want to advertise a single ecdsa algorithm size.
711
  - If there is a ecdsa hostkey at startup we choose that that size.
712
  - If we generate at runtime we choose the default ecdsa size.
713
  - Otherwise no ecdsa keys will be advertised */
714
715
  /* check if any keys were loaded at startup */
716
0
  loaded_any_ecdsa = 
717
0
    0
718
0
#if DROPBEAR_ECC_256
719
0
    || svr_opts.hostkey->ecckey256
720
0
#endif
721
0
#if DROPBEAR_ECC_384
722
0
    || svr_opts.hostkey->ecckey384
723
0
#endif
724
0
#if DROPBEAR_ECC_521
725
0
    || svr_opts.hostkey->ecckey521
726
0
#endif
727
0
    ;
728
0
  any_keys |= loaded_any_ecdsa;
729
730
  /* Or an ecdsa key could be generated at runtime */
731
0
  any_keys |= svr_opts.delay_hostkey;
732
733
  /* At most one ecdsa key size will be left enabled */
734
0
#if DROPBEAR_ECC_256
735
0
  if (!svr_opts.hostkey->ecckey256
736
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
737
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
738
0
  }
739
0
#endif
740
0
#if DROPBEAR_ECC_384
741
0
  if (!svr_opts.hostkey->ecckey384
742
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
743
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
744
0
  }
745
0
#endif
746
0
#if DROPBEAR_ECC_521
747
0
  if (!svr_opts.hostkey->ecckey521
748
0
    && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
749
0
    disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
750
0
  }
751
0
#endif
752
0
#endif /* DROPBEAR_ECDSA */
753
754
0
#if DROPBEAR_ED25519
755
0
  if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
756
0
    disablekey(DROPBEAR_SIGNATURE_ED25519);
757
0
  } else {
758
0
    any_keys = 1;
759
0
  }
760
0
#endif
761
0
#if DROPBEAR_SK_ECDSA
762
0
  disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
763
0
#endif 
764
0
#if DROPBEAR_SK_ED25519
765
0
  disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
766
0
#endif
767
768
0
  if (!any_keys) {
769
0
    dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
770
0
  }
771
0
}
772
773
0
static void load_banner(void) {
774
0
  struct stat buf;
775
0
  if (stat(svr_opts.bannerfile, &buf) != 0) {
776
0
    dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
777
0
        svr_opts.bannerfile);
778
0
    return;
779
0
  }
780
781
0
  if (buf.st_size > MAX_BANNER_SIZE) {
782
0
    dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
783
0
        MAX_BANNER_SIZE);
784
0
    return;
785
0
  }
786
787
0
  svr_opts.banner = buf_new(buf.st_size);
788
0
  if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
789
0
    dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
790
0
        svr_opts.bannerfile);
791
0
    buf_free(svr_opts.banner);
792
0
    svr_opts.banner = NULL;
793
0
    return;
794
0
  }
795
0
  buf_setpos(svr_opts.banner, 0);
796
797
0
}