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
32 svr_runopts svr_opts; /* GLOBAL */
33
34 static void printhelp(const char * progname);
35 static void addportandaddress(char* spec);
36
printhelp(const char * progname)37 static void printhelp(const char * progname) {
38
39 fprintf(stderr, "Dropbear sshd v%s\n"
40 "Usage: %s [options]\n"
41 "Options are:\n"
42 "-b bannerfile Display the contents of bannerfile"
43 " before user login\n"
44 " (default: none)\n"
45 #ifdef DROPBEAR_DSS
46 "-d dsskeyfile Use dsskeyfile for the dss host key\n"
47 " (default: %s)\n"
48 #endif
49 #ifdef DROPBEAR_RSA
50 "-r rsakeyfile Use rsakeyfile for the rsa host key\n"
51 " (default: %s)\n"
52 #endif
53 "-F Don't fork into background\n"
54 #ifdef DISABLE_SYSLOG
55 "(Syslog support not compiled in, using stderr)\n"
56 #else
57 "-E Log to stderr rather than syslog\n"
58 #endif
59 #ifdef DO_MOTD
60 "-m Don't display the motd on login\n"
61 #endif
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"
66 #endif
67 #ifdef ENABLE_SVR_LOCALTCPFWD
68 "-j Disable local port forwarding\n"
69 #endif
70 #ifdef ENABLE_SVR_REMOTETCPFWD
71 "-k Disable remote port forwarding\n"
72 "-a Allow connections to forwarded ports from any host\n"
73 #endif
74 "-p [address:]port\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"
79 " (default %s)\n"
80 #ifdef INETD_MODE
81 "-i Start for inetd\n"
82 #endif
83 #ifdef DEBUG_TRACE
84 "-v verbose\n"
85 #endif
86 ,DROPBEAR_VERSION, progname,
87 #ifdef DROPBEAR_DSS
88 DSS_PRIV_FILENAME,
89 #endif
90 #ifdef DROPBEAR_RSA
91 RSA_PRIV_FILENAME,
92 #endif
93 DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE);
94 }
95
svr_getopts(int argc,char ** argv)96 void svr_getopts(int argc, char ** argv) {
97
98 unsigned int i;
99 char ** next = 0;
100 int nextisport = 0;
101
102 /* see printhelp() for options */
103 svr_opts.rsakeyfile = NULL;
104 svr_opts.dsskeyfile = NULL;
105 svr_opts.bannerfile = NULL;
106 svr_opts.banner = NULL;
107 svr_opts.forkbg = 1;
108 svr_opts.norootlogin = 0;
109 svr_opts.noauthpass = 0;
110 svr_opts.norootpass = 0;
111 svr_opts.inetdmode = 0;
112 svr_opts.portcount = 0;
113 svr_opts.hostkey = NULL;
114 svr_opts.pidfile = DROPBEAR_PIDFILE;
115 #ifdef ENABLE_SVR_LOCALTCPFWD
116 svr_opts.nolocaltcp = 0;
117 #endif
118 #ifdef ENABLE_SVR_REMOTETCPFWD
119 svr_opts.noremotetcp = 0;
120 #endif
121 /* not yet
122 opts.ipv4 = 1;
123 opts.ipv6 = 1;
124 */
125 #ifdef DO_MOTD
126 svr_opts.domotd = 1;
127 #endif
128 #ifndef DISABLE_SYSLOG
129 svr_opts.usingsyslog = 1;
130 #endif
131 #ifdef ENABLE_SVR_REMOTETCPFWD
132 opts.listen_fwd_all = 0;
133 #endif
134
135 for (i = 1; i < (unsigned int)argc; i++) {
136 if (nextisport) {
137 addportandaddress(argv[i]);
138 nextisport = 0;
139 continue;
140 }
141
142 if (next) {
143 *next = argv[i];
144 if (*next == NULL) {
145 dropbear_exit("Invalid null argument");
146 }
147 next = 0x00;
148 continue;
149 }
150
151 if (argv[i][0] == '-') {
152 switch (argv[i][1]) {
153 case 'b':
154 next = &svr_opts.bannerfile;
155 break;
156 #ifdef DROPBEAR_DSS
157 case 'd':
158 next = &svr_opts.dsskeyfile;
159 break;
160 #endif
161 #ifdef DROPBEAR_RSA
162 case 'r':
163 next = &svr_opts.rsakeyfile;
164 break;
165 #endif
166 case 'F':
167 svr_opts.forkbg = 0;
168 break;
169 #ifndef DISABLE_SYSLOG
170 case 'E':
171 svr_opts.usingsyslog = 0;
172 break;
173 #endif
174 #ifdef ENABLE_SVR_LOCALTCPFWD
175 case 'j':
176 svr_opts.nolocaltcp = 1;
177 break;
178 #endif
179 #ifdef ENABLE_SVR_REMOTETCPFWD
180 case 'k':
181 svr_opts.noremotetcp = 1;
182 break;
183 case 'a':
184 opts.listen_fwd_all = 1;
185 break;
186 #endif
187 #ifdef INETD_MODE
188 case 'i':
189 svr_opts.inetdmode = 1;
190 break;
191 #endif
192 case 'p':
193 nextisport = 1;
194 break;
195 case 'P':
196 next = &svr_opts.pidfile;
197 break;
198 #ifdef DO_MOTD
199 /* motd is displayed by default, -m turns it off */
200 case 'm':
201 svr_opts.domotd = 0;
202 break;
203 #endif
204 case 'w':
205 svr_opts.norootlogin = 1;
206 break;
207 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
208 case 's':
209 svr_opts.noauthpass = 1;
210 break;
211 case 'g':
212 svr_opts.norootpass = 1;
213 break;
214 #endif
215 case 'h':
216 printhelp(argv[0]);
217 exit(EXIT_FAILURE);
218 break;
219 #ifdef DEBUG_TRACE
220 case 'v':
221 debug_trace = 1;
222 break;
223 #endif
224 default:
225 fprintf(stderr, "Unknown argument %s\n", argv[i]);
226 printhelp(argv[0]);
227 exit(EXIT_FAILURE);
228 break;
229 }
230 }
231 }
232
233 /* Set up listening ports */
234 if (svr_opts.portcount == 0) {
235 svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
236 svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
237 svr_opts.portcount = 1;
238 }
239
240 if (svr_opts.dsskeyfile == NULL) {
241 svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
242 }
243 if (svr_opts.rsakeyfile == NULL) {
244 svr_opts.rsakeyfile = RSA_PRIV_FILENAME;
245 }
246
247 if (svr_opts.bannerfile) {
248 struct stat buf;
249 if (stat(svr_opts.bannerfile, &buf) != 0) {
250 dropbear_exit("Error opening banner file '%s'",
251 svr_opts.bannerfile);
252 }
253
254 if (buf.st_size > MAX_BANNER_SIZE) {
255 dropbear_exit("Banner file too large, max is %d bytes",
256 MAX_BANNER_SIZE);
257 }
258
259 svr_opts.banner = buf_new(buf.st_size);
260 if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
261 dropbear_exit("Error reading banner file '%s'",
262 svr_opts.bannerfile);
263 }
264 buf_setpos(svr_opts.banner, 0);
265 }
266
267 }
268
addportandaddress(char * spec)269 static void addportandaddress(char* spec) {
270
271 char *myspec = NULL;
272
273 if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
274
275 /* We don't free it, it becomes part of the runopt state */
276 myspec = m_strdup(spec);
277
278 /* search for ':', that separates address and port */
279 svr_opts.ports[svr_opts.portcount] = strchr(myspec, ':');
280
281 if (svr_opts.ports[svr_opts.portcount] == NULL) {
282 /* no ':' -> the whole string specifies just a port */
283 svr_opts.ports[svr_opts.portcount] = myspec;
284 } else {
285 /* Split the address/port */
286 svr_opts.ports[svr_opts.portcount][0] = '\0';
287 svr_opts.ports[svr_opts.portcount]++;
288 svr_opts.addresses[svr_opts.portcount] = myspec;
289 }
290
291 if (svr_opts.addresses[svr_opts.portcount] == NULL) {
292 /* no address given -> fill in the default address */
293 svr_opts.addresses[svr_opts.portcount] = m_strdup(DROPBEAR_DEFADDRESS);
294 }
295
296 if (svr_opts.ports[svr_opts.portcount][0] == '\0') {
297 /* empty port -> exit */
298 dropbear_exit("Bad port");
299 }
300
301 svr_opts.portcount++;
302 }
303 }
304
disablekey(int type,const char * filename)305 static void disablekey(int type, const char* filename) {
306
307 int i;
308
309 for (i = 0; sshhostkey[i].name != NULL; i++) {
310 if (sshhostkey[i].val == type) {
311 sshhostkey[i].usable = 0;
312 break;
313 }
314 }
315 dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename,
316 type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
317 }
318
319 /* Must be called after syslog/etc is working */
loadhostkeys()320 void loadhostkeys() {
321
322 int ret;
323 int type;
324
325 TRACE(("enter loadhostkeys"))
326
327 svr_opts.hostkey = new_sign_key();
328
329 #ifdef DROPBEAR_RSA
330 type = DROPBEAR_SIGNKEY_RSA;
331 ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type);
332 if (ret == DROPBEAR_FAILURE) {
333 disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile);
334 }
335 #endif
336 #ifdef DROPBEAR_DSS
337 type = DROPBEAR_SIGNKEY_DSS;
338 ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type);
339 if (ret == DROPBEAR_FAILURE) {
340 disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile);
341 }
342 #endif
343
344 if ( 1
345 #ifdef DROPBEAR_DSS
346 && svr_opts.hostkey->dsskey == NULL
347 #endif
348 #ifdef DROPBEAR_RSA
349 && svr_opts.hostkey->rsakey == NULL
350 #endif
351 ) {
352 dropbear_exit("No hostkeys available");
353 }
354
355 TRACE(("leave loadhostkeys"))
356 }
357