Coverage Report

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