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 sshd v%s\n"
40 "Usage: %s [options]\n"
42 "-b bannerfile Display the contents of bannerfile"
43 " before user login\n"
46 "-d dsskeyfile Use dsskeyfile for the dss host key\n"
50 "-r rsakeyfile Use rsakeyfile for the rsa host key\n"
53 "-F Don't fork into background\n"
55 "(Syslog support not compiled in, using stderr)\n"
57 "-E Log to stderr rather than syslog\n"
60 "-m Don't display the motd on login\n"
62 "-w Disallow root logins\n"
63 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
64 "-s Disable password logins\n"
65 "-g Disable password logins for root\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)\n"
85 "-I <idle_timeout> (0 is never, default %d)\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
.inetdmode
= 0;
119 svr_opts
.portcount
= 0;
120 svr_opts
.hostkey
= NULL
;
121 svr_opts
.pidfile
= DROPBEAR_PIDFILE
;
122 #ifdef ENABLE_SVR_LOCALTCPFWD
123 svr_opts
.nolocaltcp
= 0;
125 #ifdef ENABLE_SVR_REMOTETCPFWD
126 svr_opts
.noremotetcp
= 0;
135 #ifndef DISABLE_SYSLOG
136 svr_opts
.usingsyslog
= 1;
138 opts
.recv_window
= DEFAULT_RECV_WINDOW
;
139 opts
.keepalive_secs
= DEFAULT_KEEPALIVE
;
140 opts
.idle_timeout_secs
= DEFAULT_IDLE_TIMEOUT
;
142 #ifdef ENABLE_SVR_REMOTETCPFWD
143 opts
.listen_fwd_all
= 0;
146 for (i
= 1; i
< (unsigned int)argc
; i
++) {
148 addportandaddress(argv
[i
]);
156 dropbear_exit("Invalid null argument");
162 if (argv
[i
][0] == '-') {
163 switch (argv
[i
][1]) {
165 next
= &svr_opts
.bannerfile
;
169 next
= &svr_opts
.dsskeyfile
;
174 next
= &svr_opts
.rsakeyfile
;
180 #ifndef DISABLE_SYSLOG
182 svr_opts
.usingsyslog
= 0;
185 #ifdef ENABLE_SVR_LOCALTCPFWD
187 svr_opts
.nolocaltcp
= 1;
190 #ifdef ENABLE_SVR_REMOTETCPFWD
192 svr_opts
.noremotetcp
= 1;
195 opts
.listen_fwd_all
= 1;
200 svr_opts
.inetdmode
= 1;
207 next
= &svr_opts
.pidfile
;
210 /* motd is displayed by default, -m turns it off */
216 svr_opts
.norootlogin
= 1;
219 next
= &recv_window_arg
;
222 next
= &keepalive_arg
;
225 next
= &idle_timeout_arg
;
227 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
229 svr_opts
.noauthpass
= 1;
232 svr_opts
.norootpass
= 1;
240 /* backwards compatibility with old urandom option */
248 fprintf(stderr
, "Unknown argument %s\n", argv
[i
]);
256 /* Set up listening ports */
257 if (svr_opts
.portcount
== 0) {
258 svr_opts
.ports
[0] = m_strdup(DROPBEAR_DEFPORT
);
259 svr_opts
.addresses
[0] = m_strdup(DROPBEAR_DEFADDRESS
);
260 svr_opts
.portcount
= 1;
263 if (svr_opts
.dsskeyfile
== NULL
) {
264 svr_opts
.dsskeyfile
= DSS_PRIV_FILENAME
;
266 if (svr_opts
.rsakeyfile
== NULL
) {
267 svr_opts
.rsakeyfile
= RSA_PRIV_FILENAME
;
270 if (svr_opts
.bannerfile
) {
272 if (stat(svr_opts
.bannerfile
, &buf
) != 0) {
273 dropbear_exit("Error opening banner file '%s'",
274 svr_opts
.bannerfile
);
277 if (buf
.st_size
> MAX_BANNER_SIZE
) {
278 dropbear_exit("Banner file too large, max is %d bytes",
282 svr_opts
.banner
= buf_new(buf
.st_size
);
283 if (buf_readfile(svr_opts
.banner
, svr_opts
.bannerfile
)!=DROPBEAR_SUCCESS
) {
284 dropbear_exit("Error reading banner file '%s'",
285 svr_opts
.bannerfile
);
287 buf_setpos(svr_opts
.banner
, 0);
291 if (recv_window_arg
) {
292 opts
.recv_window
= atol(recv_window_arg
);
293 if (opts
.recv_window
== 0 || opts
.recv_window
> MAX_RECV_WINDOW
) {
294 dropbear_exit("Bad recv window '%s'", recv_window_arg
);
299 if (m_str_to_uint(keepalive_arg
, &opts
.keepalive_secs
) == DROPBEAR_FAILURE
) {
300 dropbear_exit("Bad keepalive '%s'", keepalive_arg
);
304 if (idle_timeout_arg
) {
305 if (m_str_to_uint(idle_timeout_arg
, &opts
.idle_timeout_secs
) == DROPBEAR_FAILURE
) {
306 dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg
);
311 static void addportandaddress(char* spec
) {
315 if (svr_opts
.portcount
< DROPBEAR_MAX_PORTS
) {
317 /* We don't free it, it becomes part of the runopt state */
318 myspec
= m_strdup(spec
);
320 /* search for ':', that separates address and port */
321 svr_opts
.ports
[svr_opts
.portcount
] = strchr(myspec
, ':');
323 if (svr_opts
.ports
[svr_opts
.portcount
] == NULL
) {
324 /* no ':' -> the whole string specifies just a port */
325 svr_opts
.ports
[svr_opts
.portcount
] = myspec
;
327 /* Split the address/port */
328 svr_opts
.ports
[svr_opts
.portcount
][0] = '\0';
329 svr_opts
.ports
[svr_opts
.portcount
]++;
330 svr_opts
.addresses
[svr_opts
.portcount
] = myspec
;
333 if (svr_opts
.addresses
[svr_opts
.portcount
] == NULL
) {
334 /* no address given -> fill in the default address */
335 svr_opts
.addresses
[svr_opts
.portcount
] = m_strdup(DROPBEAR_DEFADDRESS
);
338 if (svr_opts
.ports
[svr_opts
.portcount
][0] == '\0') {
339 /* empty port -> exit */
340 dropbear_exit("Bad port");
343 svr_opts
.portcount
++;
347 static void disablekey(int type
, const char* filename
) {
351 for (i
= 0; sshhostkey
[i
].name
!= NULL
; i
++) {
352 if (sshhostkey
[i
].val
== type
) {
353 sshhostkey
[i
].usable
= 0;
357 dropbear_log(LOG_WARNING
, "Failed reading '%s', disabling %s", filename
,
358 type
== DROPBEAR_SIGNKEY_DSS
? "DSS" : "RSA");
361 /* Must be called after syslog/etc is working */
362 void loadhostkeys() {
367 TRACE(("enter loadhostkeys"))
369 svr_opts
.hostkey
= new_sign_key();
372 type
= DROPBEAR_SIGNKEY_RSA
;
373 ret
= readhostkey(svr_opts
.rsakeyfile
, svr_opts
.hostkey
, &type
);
374 if (ret
== DROPBEAR_FAILURE
) {
375 disablekey(DROPBEAR_SIGNKEY_RSA
, svr_opts
.rsakeyfile
);
379 type
= DROPBEAR_SIGNKEY_DSS
;
380 ret
= readhostkey(svr_opts
.dsskeyfile
, svr_opts
.hostkey
, &type
);
381 if (ret
== DROPBEAR_FAILURE
) {
382 disablekey(DROPBEAR_SIGNKEY_DSS
, svr_opts
.dsskeyfile
);
388 && svr_opts
.hostkey
->dsskey
== NULL
391 && svr_opts
.hostkey
->rsakey
== NULL
394 dropbear_exit("No hostkeys available");
397 TRACE(("leave loadhostkeys"))