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
32 svr_runopts svr_opts
; /* GLOBAL */
34 static void printhelp(const char * progname
);
35 static void addportandaddress(char* spec
);
37 static void printhelp(const char * progname
) {
39 fprintf(stderr
, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
40 "Usage: %s [options]\n"
41 "-b bannerfile Display the contents of bannerfile"
42 " before user login\n"
45 "-d dsskeyfile Use dsskeyfile for the DSS host key\n"
49 "-r rsakeyfile Use rsakeyfile for the RSA host key\n"
52 "-F Don't fork into background\n"
54 "(Syslog support not compiled in, using stderr)\n"
56 "-E Log to stderr rather than syslog\n"
59 "-m Don't display the motd on login\n"
61 "-w Disallow root logins\n"
62 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
63 "-s Disable password logins\n"
64 "-g Disable password logins for root\n"
65 "-B Allow blank password logins\n"
67 #ifdef ENABLE_SVR_LOCALTCPFWD
68 "-j Disable local port forwarding\n"
70 #ifdef ENABLE_SVR_REMOTETCPFWD
71 "-k Disable remote port forwarding\n"
72 "-a Allow connections to forwarded ports from any host\n"
75 " Listen on specified tcp port (and optionally address),\n"
76 " up to %d can be specified\n"
77 " (default port is %s if none specified)\n"
78 "-P PidFile Create pid file PidFile\n"
81 "-i Start for inetd\n"
83 "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
84 "-K <keepalive> (0 is never, default %d, in seconds)\n"
85 "-I <idle_timeout> (0 is never, default %d, in seconds)\n"
87 "-v verbose (compiled with DEBUG_TRACE)\n"
89 ,DROPBEAR_VERSION
, progname
,
96 DROPBEAR_MAX_PORTS
, DROPBEAR_DEFPORT
, DROPBEAR_PIDFILE
,
97 DEFAULT_RECV_WINDOW
, DEFAULT_KEEPALIVE
, DEFAULT_IDLE_TIMEOUT
);
100 void svr_getopts(int argc
, char ** argv
) {
105 char* recv_window_arg
= NULL
;
106 char* keepalive_arg
= NULL
;
107 char* idle_timeout_arg
= NULL
;
109 /* see printhelp() for options */
110 svr_opts
.rsakeyfile
= NULL
;
111 svr_opts
.dsskeyfile
= NULL
;
112 svr_opts
.bannerfile
= NULL
;
113 svr_opts
.banner
= NULL
;
115 svr_opts
.norootlogin
= 0;
116 svr_opts
.noauthpass
= 0;
117 svr_opts
.norootpass
= 0;
118 svr_opts
.allowblankpass
= 0;
119 svr_opts
.inetdmode
= 0;
120 svr_opts
.portcount
= 0;
121 svr_opts
.hostkey
= NULL
;
122 svr_opts
.pidfile
= DROPBEAR_PIDFILE
;
123 #ifdef ENABLE_SVR_LOCALTCPFWD
124 svr_opts
.nolocaltcp
= 0;
126 #ifdef ENABLE_SVR_REMOTETCPFWD
127 svr_opts
.noremotetcp
= 0;
130 opts
.enable_compress
= 1;
139 #ifndef DISABLE_SYSLOG
140 svr_opts
.usingsyslog
= 1;
142 opts
.recv_window
= DEFAULT_RECV_WINDOW
;
143 opts
.keepalive_secs
= DEFAULT_KEEPALIVE
;
144 opts
.idle_timeout_secs
= DEFAULT_IDLE_TIMEOUT
;
146 #ifdef ENABLE_SVR_REMOTETCPFWD
147 opts
.listen_fwd_all
= 0;
150 for (i
= 1; i
< (unsigned int)argc
; i
++) {
152 addportandaddress(argv
[i
]);
160 dropbear_exit("Invalid null argument");
166 if (argv
[i
][0] == '-') {
167 switch (argv
[i
][1]) {
169 next
= &svr_opts
.bannerfile
;
173 next
= &svr_opts
.dsskeyfile
;
178 next
= &svr_opts
.rsakeyfile
;
184 #ifndef DISABLE_SYSLOG
186 svr_opts
.usingsyslog
= 0;
189 #ifdef ENABLE_SVR_LOCALTCPFWD
191 svr_opts
.nolocaltcp
= 1;
194 #ifdef ENABLE_SVR_REMOTETCPFWD
196 svr_opts
.noremotetcp
= 1;
199 opts
.listen_fwd_all
= 1;
204 svr_opts
.inetdmode
= 1;
211 next
= &svr_opts
.pidfile
;
214 /* motd is displayed by default, -m turns it off */
220 svr_opts
.norootlogin
= 1;
223 next
= &recv_window_arg
;
226 next
= &keepalive_arg
;
229 next
= &idle_timeout_arg
;
231 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
233 svr_opts
.noauthpass
= 1;
236 svr_opts
.norootpass
= 1;
239 svr_opts
.allowblankpass
= 1;
247 /* backwards compatibility with old urandom option */
255 fprintf(stderr
, "Unknown argument %s\n", argv
[i
]);
263 /* Set up listening ports */
264 if (svr_opts
.portcount
== 0) {
265 svr_opts
.ports
[0] = m_strdup(DROPBEAR_DEFPORT
);
266 svr_opts
.addresses
[0] = m_strdup(DROPBEAR_DEFADDRESS
);
267 svr_opts
.portcount
= 1;
270 if (svr_opts
.dsskeyfile
== NULL
) {
271 svr_opts
.dsskeyfile
= DSS_PRIV_FILENAME
;
273 if (svr_opts
.rsakeyfile
== NULL
) {
274 svr_opts
.rsakeyfile
= RSA_PRIV_FILENAME
;
277 if (svr_opts
.bannerfile
) {
279 if (stat(svr_opts
.bannerfile
, &buf
) != 0) {
280 dropbear_exit("Error opening banner file '%s'",
281 svr_opts
.bannerfile
);
284 if (buf
.st_size
> MAX_BANNER_SIZE
) {
285 dropbear_exit("Banner file too large, max is %d bytes",
289 svr_opts
.banner
= buf_new(buf
.st_size
);
290 if (buf_readfile(svr_opts
.banner
, svr_opts
.bannerfile
)!=DROPBEAR_SUCCESS
) {
291 dropbear_exit("Error reading banner file '%s'",
292 svr_opts
.bannerfile
);
294 buf_setpos(svr_opts
.banner
, 0);
298 if (recv_window_arg
) {
299 opts
.recv_window
= atol(recv_window_arg
);
300 if (opts
.recv_window
== 0 || opts
.recv_window
> MAX_RECV_WINDOW
) {
301 dropbear_exit("Bad recv window '%s'", recv_window_arg
);
307 if (m_str_to_uint(keepalive_arg
, &val
) == DROPBEAR_FAILURE
) {
308 dropbear_exit("Bad keepalive '%s'", keepalive_arg
);
310 opts
.keepalive_secs
= val
;
313 if (idle_timeout_arg
) {
315 if (m_str_to_uint(idle_timeout_arg
, &val
) == DROPBEAR_FAILURE
) {
316 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg
);
318 opts
.idle_timeout_secs
= val
;
322 static void addportandaddress(char* spec
) {
326 if (svr_opts
.portcount
< DROPBEAR_MAX_PORTS
) {
328 /* We don't free it, it becomes part of the runopt state */
329 myspec
= m_strdup(spec
);
331 if (myspec
[0] == '[') {
333 svr_opts
.ports
[svr_opts
.portcount
] = strchr(myspec
, ']');
334 if (svr_opts
.ports
[svr_opts
.portcount
] == NULL
) {
335 /* Unmatched [ -> exit */
336 dropbear_exit("Bad listen address");
338 svr_opts
.ports
[svr_opts
.portcount
][0] = '\0';
339 svr_opts
.ports
[svr_opts
.portcount
]++;
340 if (svr_opts
.ports
[svr_opts
.portcount
][0] != ':') {
341 /* Missing port -> exit */
342 dropbear_exit("Missing port");
345 /* search for ':', that separates address and port */
346 svr_opts
.ports
[svr_opts
.portcount
] = strrchr(myspec
, ':');
349 if (svr_opts
.ports
[svr_opts
.portcount
] == NULL
) {
350 /* no ':' -> the whole string specifies just a port */
351 svr_opts
.ports
[svr_opts
.portcount
] = myspec
;
353 /* Split the address/port */
354 svr_opts
.ports
[svr_opts
.portcount
][0] = '\0';
355 svr_opts
.ports
[svr_opts
.portcount
]++;
356 svr_opts
.addresses
[svr_opts
.portcount
] = myspec
;
359 if (svr_opts
.addresses
[svr_opts
.portcount
] == NULL
) {
360 /* no address given -> fill in the default address */
361 svr_opts
.addresses
[svr_opts
.portcount
] = m_strdup(DROPBEAR_DEFADDRESS
);
364 if (svr_opts
.ports
[svr_opts
.portcount
][0] == '\0') {
365 /* empty port -> exit */
366 dropbear_exit("Bad port");
369 svr_opts
.portcount
++;
373 static void disablekey(int type
, const char* filename
) {
377 for (i
= 0; sshhostkey
[i
].name
!= NULL
; i
++) {
378 if (sshhostkey
[i
].val
== type
) {
379 sshhostkey
[i
].usable
= 0;
383 dropbear_log(LOG_WARNING
, "Failed reading '%s', disabling %s", filename
,
384 type
== DROPBEAR_SIGNKEY_DSS
? "DSS" : "RSA");
387 /* Must be called after syslog/etc is working */
388 void loadhostkeys() {
393 TRACE(("enter loadhostkeys"))
395 svr_opts
.hostkey
= new_sign_key();
398 type
= DROPBEAR_SIGNKEY_RSA
;
399 ret
= readhostkey(svr_opts
.rsakeyfile
, svr_opts
.hostkey
, &type
);
400 if (ret
== DROPBEAR_FAILURE
) {
401 disablekey(DROPBEAR_SIGNKEY_RSA
, svr_opts
.rsakeyfile
);
405 type
= DROPBEAR_SIGNKEY_DSS
;
406 ret
= readhostkey(svr_opts
.dsskeyfile
, svr_opts
.hostkey
, &type
);
407 if (ret
== DROPBEAR_FAILURE
) {
408 disablekey(DROPBEAR_SIGNKEY_DSS
, svr_opts
.dsskeyfile
);
414 && svr_opts
.hostkey
->dsskey
== NULL
417 && svr_opts
.hostkey
->rsakey
== NULL
420 dropbear_exit("No hostkeys available");
423 TRACE(("leave loadhostkeys"))