2 * Dropbear - a SSH2 server
4 * Copyright (c) 2002,2003 Matt Johnston
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
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"
47 "-r keyfile Specify hostkeys (repeatable)\n"
58 #ifdef DROPBEAR_DELAY_HOSTKEY
59 "-R Create hostkeys as required\n"
61 "-F Don't fork into background\n"
63 "(Syslog support not compiled in, using stderr)\n"
65 "-E Log to stderr rather than syslog\n"
68 "-m Don't display the motd on login\n"
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"
76 #ifdef ENABLE_SVR_LOCALTCPFWD
77 "-j Disable local port forwarding\n"
79 #ifdef ENABLE_SVR_REMOTETCPFWD
80 "-k Disable remote port forwarding\n"
81 "-a Allow connections to forwarded ports from any host\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"
90 "-i Start for inetd\n"
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"
97 "-v verbose (compiled with DEBUG_TRACE)\n"
99 ,DROPBEAR_VERSION
, progname
,
106 #ifdef DROPBEAR_ECDSA
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
) {
118 char* recv_window_arg
= NULL
;
119 char* keepalive_arg
= NULL
;
120 char* idle_timeout_arg
= NULL
;
121 char* keyfile
= NULL
;
125 /* see printhelp() for options */
126 svr_opts
.bannerfile
= NULL
;
127 svr_opts
.banner
= NULL
;
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;
141 #ifdef ENABLE_SVR_REMOTETCPFWD
142 svr_opts
.noremotetcp
= 0;
146 #if DROPBEAR_SERVER_DELAY_ZLIB
147 opts
.compress_mode
= DROPBEAR_COMPRESS_DELAYED
;
149 opts
.compress_mode
= DROPBEAR_COMPRESS_ON
;
160 #ifndef DISABLE_SYSLOG
161 svr_opts
.usingsyslog
= 1;
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;
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
++) {
178 next
= &svr_opts
.bannerfile
;
185 svr_opts
.delay_hostkey
= 1;
190 #ifndef DISABLE_SYSLOG
192 svr_opts
.usingsyslog
= 0;
195 #ifdef ENABLE_SVR_LOCALTCPFWD
197 svr_opts
.nolocaltcp
= 1;
200 #ifdef ENABLE_SVR_REMOTETCPFWD
202 svr_opts
.noremotetcp
= 1;
205 opts
.listen_fwd_all
= 1;
210 svr_opts
.inetdmode
= 1;
217 next
= &svr_opts
.pidfile
;
220 /* motd is displayed by default, -m turns it off */
226 svr_opts
.norootlogin
= 1;
229 next
= &recv_window_arg
;
232 next
= &keepalive_arg
;
235 next
= &idle_timeout_arg
;
237 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
239 svr_opts
.noauthpass
= 1;
242 svr_opts
.norootpass
= 1;
245 svr_opts
.allowblankpass
= 1;
253 /* backwards compatibility with old urandom option */
265 fprintf(stderr
, "Invalid option -%c\n", c
);
272 if (!next
&& !nextisport
)
279 dropbear_exit("Missing argument");
284 addportandaddress(&argv
[i
][j
]);
289 dropbear_exit("Invalid null argument");
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
) {
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",
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
);
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
) {
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
);
360 if (myspec
[0] == '[') {
362 port
= strchr(myspec
, ']');
364 /* Unmatched [ -> exit */
365 dropbear_exit("Bad listen address");
369 if (port
[0] != ':') {
370 /* Missing port -> exit */
371 dropbear_exit("Missing port");
374 /* search for ':', that separates address and port */
375 port
= strrchr(myspec
, ':');
379 /* no ':' -> the whole string specifies just a port */
382 /* Split the address/port */
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
++;
404 static void disablekey(int type
) {
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;
415 static void loadhostkey_helper(const char *name
, void** src
, void** dst
, int fatal_duplicate
) {
417 if (fatal_duplicate
) {
418 dropbear_exit("Only one %s key can be specified", name
);
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
);
438 if (type
== DROPBEAR_SIGNKEY_RSA
) {
439 loadhostkey_helper("RSA", (void**)&read_key
->rsakey
, (void**)&svr_opts
.hostkey
->rsakey
, fatal_duplicate
);
444 if (type
== DROPBEAR_SIGNKEY_DSS
) {
445 loadhostkey_helper("DSS", (void**)&read_key
->dsskey
, (void**)&svr_opts
.hostkey
->dsskey
, fatal_duplicate
);
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
);
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
);
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
);
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() {
480 int disable_unset_keys
= 1;
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
);
492 loadhostkey(RSA_PRIV_FILENAME
, 0);
496 loadhostkey(DSS_PRIV_FILENAME
, 0);
499 #ifdef DROPBEAR_ECDSA
500 loadhostkey(ECDSA_PRIV_FILENAME
, 0);
503 #ifdef DROPBEAR_DELAY_HOSTKEY
504 if (svr_opts
.delay_hostkey
) {
505 disable_unset_keys
= 0;
510 if (disable_unset_keys
&& !svr_opts
.hostkey
->rsakey
) {
511 disablekey(DROPBEAR_SIGNKEY_RSA
);
518 if (disable_unset_keys
&& !svr_opts
.hostkey
->dsskey
) {
519 disablekey(DROPBEAR_SIGNKEY_DSS
);
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
);
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
);
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
);
553 #endif /* DROPBEAR_ECDSA */
556 dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");