dropbear 2016.73
[tomato.git] / release / src / router / dropbear / svr-runopts.c
blob8f60059fee2252dc3ccc3ee6a50d63de63989556
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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. */
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"
33 svr_runopts svr_opts; /* GLOBAL */
35 static void printhelp(const char * progname);
36 static void addportandaddress(const char* spec);
37 static void loadhostkey(const char *keyfile, int fatal_duplicate);
38 static void addhostkey(const char *keyfile);
40 static void printhelp(const char * progname) {
42 fprintf(stderr, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
43 "Usage: %s [options]\n"
44 "-b bannerfile Display the contents of bannerfile"
45 " before user login\n"
46 " (default: none)\n"
47 "-r keyfile Specify hostkeys (repeatable)\n"
48 " defaults: \n"
49 #ifdef DROPBEAR_DSS
50 " dss %s\n"
51 #endif
52 #ifdef DROPBEAR_RSA
53 " rsa %s\n"
54 #endif
55 #ifdef DROPBEAR_ECDSA
56 " ecdsa %s\n"
57 #endif
58 #ifdef DROPBEAR_DELAY_HOSTKEY
59 "-R Create hostkeys as required\n"
60 #endif
61 "-F Don't fork into background\n"
62 #ifdef DISABLE_SYSLOG
63 "(Syslog support not compiled in, using stderr)\n"
64 #else
65 "-E Log to stderr rather than syslog\n"
66 #endif
67 #ifdef DO_MOTD
68 "-m Don't display the motd on login\n"
69 #endif
70 "-w Disallow root logins\n"
71 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
72 "-s Disable password logins\n"
73 "-g Disable password logins for root\n"
74 "-B Allow blank password logins\n"
75 #endif
76 #ifdef ENABLE_SVR_LOCALTCPFWD
77 "-j Disable local port forwarding\n"
78 #endif
79 #ifdef ENABLE_SVR_REMOTETCPFWD
80 "-k Disable remote port forwarding\n"
81 "-a Allow connections to forwarded ports from any host\n"
82 #endif
83 "-p [address:]port\n"
84 " Listen on specified tcp port (and optionally address),\n"
85 " up to %d can be specified\n"
86 " (default port is %s if none specified)\n"
87 "-P PidFile Create pid file PidFile\n"
88 " (default %s)\n"
89 #ifdef INETD_MODE
90 "-i Start for inetd\n"
91 #endif
92 "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
93 "-K <keepalive> (0 is never, default %d, in seconds)\n"
94 "-I <idle_timeout> (0 is never, default %d, in seconds)\n"
95 "-V Version\n"
96 #ifdef DEBUG_TRACE
97 "-v verbose (compiled with DEBUG_TRACE)\n"
98 #endif
99 ,DROPBEAR_VERSION, progname,
100 #ifdef DROPBEAR_DSS
101 DSS_PRIV_FILENAME,
102 #endif
103 #ifdef DROPBEAR_RSA
104 RSA_PRIV_FILENAME,
105 #endif
106 #ifdef DROPBEAR_ECDSA
107 ECDSA_PRIV_FILENAME,
108 #endif
109 DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
110 DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
113 void svr_getopts(int argc, char ** argv) {
115 unsigned int i, j;
116 char ** next = 0;
117 int nextisport = 0;
118 char* recv_window_arg = NULL;
119 char* keepalive_arg = NULL;
120 char* idle_timeout_arg = NULL;
121 char* keyfile = NULL;
122 char c;
125 /* see printhelp() for options */
126 svr_opts.bannerfile = NULL;
127 svr_opts.banner = NULL;
128 svr_opts.forkbg = 1;
129 svr_opts.norootlogin = 0;
130 svr_opts.noauthpass = 0;
131 svr_opts.norootpass = 0;
132 svr_opts.allowblankpass = 0;
133 svr_opts.inetdmode = 0;
134 svr_opts.portcount = 0;
135 svr_opts.hostkey = NULL;
136 svr_opts.delay_hostkey = 0;
137 svr_opts.pidfile = DROPBEAR_PIDFILE;
138 #ifdef ENABLE_SVR_LOCALTCPFWD
139 svr_opts.nolocaltcp = 0;
140 #endif
141 #ifdef ENABLE_SVR_REMOTETCPFWD
142 svr_opts.noremotetcp = 0;
143 #endif
145 #ifndef DISABLE_ZLIB
146 #if DROPBEAR_SERVER_DELAY_ZLIB
147 opts.compress_mode = DROPBEAR_COMPRESS_DELAYED;
148 #else
149 opts.compress_mode = DROPBEAR_COMPRESS_ON;
150 #endif
151 #endif
153 /* not yet
154 opts.ipv4 = 1;
155 opts.ipv6 = 1;
157 #ifdef DO_MOTD
158 svr_opts.domotd = 1;
159 #endif
160 #ifndef DISABLE_SYSLOG
161 opts.usingsyslog = 1;
162 #endif
163 opts.recv_window = DEFAULT_RECV_WINDOW;
164 opts.keepalive_secs = DEFAULT_KEEPALIVE;
165 opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
167 #ifdef ENABLE_SVR_REMOTETCPFWD
168 opts.listen_fwd_all = 0;
169 #endif
171 for (i = 1; i < (unsigned int)argc; i++) {
172 if (argv[i][0] != '-' || argv[i][1] == '\0')
173 dropbear_exit("Invalid argument: %s", argv[i]);
175 for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
176 switch (c) {
177 case 'b':
178 next = &svr_opts.bannerfile;
179 break;
180 case 'd':
181 case 'r':
182 next = &keyfile;
183 break;
184 case 'R':
185 svr_opts.delay_hostkey = 1;
186 break;
187 case 'F':
188 svr_opts.forkbg = 0;
189 break;
190 #ifndef DISABLE_SYSLOG
191 case 'E':
192 opts.usingsyslog = 0;
193 break;
194 #endif
195 #ifdef ENABLE_SVR_LOCALTCPFWD
196 case 'j':
197 svr_opts.nolocaltcp = 1;
198 break;
199 #endif
200 #ifdef ENABLE_SVR_REMOTETCPFWD
201 case 'k':
202 svr_opts.noremotetcp = 1;
203 break;
204 case 'a':
205 opts.listen_fwd_all = 1;
206 break;
207 #endif
208 #ifdef INETD_MODE
209 case 'i':
210 svr_opts.inetdmode = 1;
211 break;
212 #endif
213 case 'p':
214 nextisport = 1;
215 break;
216 case 'P':
217 next = &svr_opts.pidfile;
218 break;
219 #ifdef DO_MOTD
220 /* motd is displayed by default, -m turns it off */
221 case 'm':
222 svr_opts.domotd = 0;
223 break;
224 #endif
225 case 'w':
226 svr_opts.norootlogin = 1;
227 break;
228 case 'W':
229 next = &recv_window_arg;
230 break;
231 case 'K':
232 next = &keepalive_arg;
233 break;
234 case 'I':
235 next = &idle_timeout_arg;
236 break;
237 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
238 case 's':
239 svr_opts.noauthpass = 1;
240 break;
241 case 'g':
242 svr_opts.norootpass = 1;
243 break;
244 case 'B':
245 svr_opts.allowblankpass = 1;
246 break;
247 #endif
248 case 'h':
249 printhelp(argv[0]);
250 exit(EXIT_SUCCESS);
251 break;
252 case 'u':
253 /* backwards compatibility with old urandom option */
254 break;
255 #ifdef DEBUG_TRACE
256 case 'v':
257 debug_trace = 1;
258 break;
259 #endif
260 case 'V':
261 print_version();
262 exit(EXIT_SUCCESS);
263 break;
264 default:
265 fprintf(stderr, "Invalid option -%c\n", c);
266 printhelp(argv[0]);
267 exit(EXIT_FAILURE);
268 break;
272 if (!next && !nextisport)
273 continue;
275 if (c == '\0') {
276 i++;
277 j = 0;
278 if (!argv[i]) {
279 dropbear_exit("Missing argument");
283 if (nextisport) {
284 addportandaddress(&argv[i][j]);
285 nextisport = 0;
286 } else if (next) {
287 *next = &argv[i][j];
288 if (*next == NULL) {
289 dropbear_exit("Invalid null argument");
291 next = 0x00;
293 if (keyfile) {
294 addhostkey(keyfile);
295 keyfile = NULL;
300 /* Set up listening ports */
301 if (svr_opts.portcount == 0) {
302 svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
303 svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
304 svr_opts.portcount = 1;
307 if (svr_opts.bannerfile) {
308 struct stat buf;
309 if (stat(svr_opts.bannerfile, &buf) != 0) {
310 dropbear_exit("Error opening banner file '%s'",
311 svr_opts.bannerfile);
314 if (buf.st_size > MAX_BANNER_SIZE) {
315 dropbear_exit("Banner file too large, max is %d bytes",
316 MAX_BANNER_SIZE);
319 svr_opts.banner = buf_new(buf.st_size);
320 if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
321 dropbear_exit("Error reading banner file '%s'",
322 svr_opts.bannerfile);
324 buf_setpos(svr_opts.banner, 0);
327 if (recv_window_arg) {
328 opts.recv_window = atol(recv_window_arg);
329 if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
330 dropbear_exit("Bad recv window '%s'", recv_window_arg);
334 if (keepalive_arg) {
335 unsigned int val;
336 if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
337 dropbear_exit("Bad keepalive '%s'", keepalive_arg);
339 opts.keepalive_secs = val;
342 if (idle_timeout_arg) {
343 unsigned int val;
344 if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
345 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
347 opts.idle_timeout_secs = val;
351 static void addportandaddress(const char* spec) {
352 char *spec_copy = NULL, *myspec = NULL, *port = NULL, *address = NULL;
354 if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
356 /* We don't free it, it becomes part of the runopt state */
357 spec_copy = m_strdup(spec);
358 myspec = spec_copy;
360 if (myspec[0] == '[') {
361 myspec++;
362 port = strchr(myspec, ']');
363 if (!port) {
364 /* Unmatched [ -> exit */
365 dropbear_exit("Bad listen address");
367 port[0] = '\0';
368 port++;
369 if (port[0] != ':') {
370 /* Missing port -> exit */
371 dropbear_exit("Missing port");
373 } else {
374 /* search for ':', that separates address and port */
375 port = strrchr(myspec, ':');
378 if (!port) {
379 /* no ':' -> the whole string specifies just a port */
380 port = myspec;
381 } else {
382 /* Split the address/port */
383 port[0] = '\0';
384 port++;
385 address = myspec;
388 if (!address) {
389 /* no address given -> fill in the default address */
390 address = DROPBEAR_DEFADDRESS;
393 if (port[0] == '\0') {
394 /* empty port -> exit */
395 dropbear_exit("Bad port");
397 svr_opts.ports[svr_opts.portcount] = m_strdup(port);
398 svr_opts.addresses[svr_opts.portcount] = m_strdup(address);
399 svr_opts.portcount++;
400 m_free(spec_copy);
404 static void disablekey(int type) {
405 int i;
406 TRACE(("Disabling key type %d", type))
407 for (i = 0; sshhostkey[i].name != NULL; i++) {
408 if (sshhostkey[i].val == type) {
409 sshhostkey[i].usable = 0;
410 break;
415 static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
416 if (*dst) {
417 if (fatal_duplicate) {
418 dropbear_exit("Only one %s key can be specified", name);
420 } else {
421 *dst = *src;
422 *src = NULL;
427 /* Must be called after syslog/etc is working */
428 static void loadhostkey(const char *keyfile, int fatal_duplicate) {
429 sign_key * read_key = new_sign_key();
430 enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
431 if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
432 if (!svr_opts.delay_hostkey) {
433 dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
437 #ifdef DROPBEAR_RSA
438 if (type == DROPBEAR_SIGNKEY_RSA) {
439 loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
441 #endif
443 #ifdef DROPBEAR_DSS
444 if (type == DROPBEAR_SIGNKEY_DSS) {
445 loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
447 #endif
449 #ifdef DROPBEAR_ECDSA
450 #ifdef DROPBEAR_ECC_256
451 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
452 loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
454 #endif
455 #ifdef DROPBEAR_ECC_384
456 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
457 loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
459 #endif
460 #ifdef DROPBEAR_ECC_521
461 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
462 loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
464 #endif
465 #endif /* DROPBEAR_ECDSA */
466 sign_key_free(read_key);
467 TRACE(("leave loadhostkey"))
470 static void addhostkey(const char *keyfile) {
471 if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
472 dropbear_exit("Too many hostkeys");
474 svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
475 svr_opts.num_hostkey_files++;
478 void load_all_hostkeys() {
479 int i;
480 int disable_unset_keys = 1;
481 int any_keys = 0;
483 svr_opts.hostkey = new_sign_key();
485 for (i = 0; i < svr_opts.num_hostkey_files; i++) {
486 char *hostkey_file = svr_opts.hostkey_files[i];
487 loadhostkey(hostkey_file, 1);
488 m_free(hostkey_file);
491 #ifdef DROPBEAR_RSA
492 loadhostkey(RSA_PRIV_FILENAME, 0);
493 #endif
495 #ifdef DROPBEAR_DSS
496 loadhostkey(DSS_PRIV_FILENAME, 0);
497 #endif
499 #ifdef DROPBEAR_ECDSA
500 loadhostkey(ECDSA_PRIV_FILENAME, 0);
501 #endif
503 #ifdef DROPBEAR_DELAY_HOSTKEY
504 if (svr_opts.delay_hostkey) {
505 disable_unset_keys = 0;
507 #endif
509 #ifdef DROPBEAR_RSA
510 if (disable_unset_keys && !svr_opts.hostkey->rsakey) {
511 disablekey(DROPBEAR_SIGNKEY_RSA);
512 } else {
513 any_keys = 1;
515 #endif
517 #ifdef DROPBEAR_DSS
518 if (disable_unset_keys && !svr_opts.hostkey->dsskey) {
519 disablekey(DROPBEAR_SIGNKEY_DSS);
520 } else {
521 any_keys = 1;
523 #endif
526 #ifdef DROPBEAR_ECDSA
527 #ifdef DROPBEAR_ECC_256
528 if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256)
529 && !svr_opts.hostkey->ecckey256) {
530 disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
531 } else {
532 any_keys = 1;
534 #endif
536 #ifdef DROPBEAR_ECC_384
537 if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384)
538 && !svr_opts.hostkey->ecckey384) {
539 disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
540 } else {
541 any_keys = 1;
543 #endif
545 #ifdef DROPBEAR_ECC_521
546 if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
547 && !svr_opts.hostkey->ecckey521) {
548 disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
549 } else {
550 any_keys = 1;
552 #endif
553 #endif /* DROPBEAR_ECDSA */
555 if (!any_keys) {
556 dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");