• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Dropbear - a SSH2 server
3  *
4  * Copyright (c) 2002-2006 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 "dbutil.h"
27 #include "session.h"
28 #include "buffer.h"
29 #include "signkey.h"
30 #include "runopts.h"
31 #include "random.h"
32 
33 static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
34 static void sigchld_handler(int dummy);
35 static void sigsegv_handler(int);
36 static void sigintterm_handler(int fish);
37 #ifdef INETD_MODE
38 static void main_inetd();
39 #endif
40 #ifdef NON_INETD_MODE
41 static void main_noinetd();
42 #endif
43 static void commonsetup();
44 
45 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI)
46 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI)
dropbear_main(int argc,char ** argv)47 int dropbear_main(int argc, char ** argv)
48 #else
49 int main(int argc, char ** argv)
50 #endif
51 {
52 	_dropbear_exit = svr_dropbear_exit;
53 	_dropbear_log = svr_dropbear_log;
54 
55 	disallow_core();
56 
57 	/* get commandline options */
58 	svr_getopts(argc, argv);
59 
60 #ifdef INETD_MODE
61 	/* service program mode */
62 	if (svr_opts.inetdmode) {
63 		main_inetd();
64 		/* notreached */
65 	}
66 #endif
67 
68 #ifdef NON_INETD_MODE
69 	main_noinetd();
70 	/* notreached */
71 #endif
72 
73 	dropbear_exit("Compiled without normal mode, can't run without -i\n");
74 	return -1;
75 }
76 #endif
77 
78 #ifdef INETD_MODE
main_inetd()79 static void main_inetd() {
80 
81 	struct sockaddr_storage remoteaddr;
82 	socklen_t remoteaddrlen;
83 	char * addrstring = NULL;
84 
85 	/* Set up handlers, syslog, seed random */
86 	commonsetup();
87 
88 	remoteaddrlen = sizeof(remoteaddr);
89 	if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) {
90 		dropbear_exit("Unable to getpeername: %s", strerror(errno));
91 	}
92 
93 	/* In case our inetd was lax in logging source addresses */
94 	addrstring = getaddrstring(&remoteaddr, 1);
95 	dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
96 
97 	/* Don't check the return value - it may just fail since inetd has
98 	 * already done setsid() after forking (xinetd on Darwin appears to do
99 	 * this */
100 	setsid();
101 
102 	/* Start service program
103 	 * -1 is a dummy childpipe, just something we can close() without
104 	 * mattering. */
105 	svr_session(0, -1, getaddrhostname(&remoteaddr), addrstring);
106 
107 	/* notreached */
108 }
109 #endif /* INETD_MODE */
110 
111 #ifdef NON_INETD_MODE
main_noinetd()112 void main_noinetd() {
113 	fd_set fds;
114 	struct timeval seltimeout;
115 	unsigned int i, j;
116 	int val;
117 	int maxsock = -1;
118 	int listensocks[MAX_LISTEN_ADDR];
119 	size_t listensockcount = 0;
120 	FILE *pidfile = NULL;
121 
122 	int childpipes[MAX_UNAUTH_CLIENTS];
123 	char * preauth_addrs[MAX_UNAUTH_CLIENTS];
124 
125 	int childsock;
126 	int childpipe[2];
127 
128 	/* Note: commonsetup() must happen before we daemon()ise. Otherwise
129 	   daemon() will chdir("/"), and we won't be able to find local-dir
130 	   hostkeys. */
131 	commonsetup();
132 
133 	/* fork */
134 	if (svr_opts.forkbg) {
135 		int closefds = 0;
136 #ifndef DEBUG_TRACE
137 		if (!svr_opts.usingsyslog) {
138 			closefds = 1;
139 		}
140 #endif
141 		if (daemon(0, closefds) < 0) {
142 			dropbear_exit("Failed to daemonize: %s", strerror(errno));
143 		}
144 	}
145 
146 	/* should be done after syslog is working */
147 	if (svr_opts.forkbg) {
148 		dropbear_log(LOG_INFO, "Running in background");
149 	} else {
150 		dropbear_log(LOG_INFO, "Not forking");
151 	}
152 
153 	/* create a PID file so that we can be killed easily */
154 	pidfile = fopen(svr_opts.pidfile, "w");
155 	if (pidfile) {
156 		fprintf(pidfile, "%d\n", getpid());
157 		fclose(pidfile);
158 	}
159 
160 	/* sockets to identify pre-authenticated clients */
161 	for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
162 		childpipes[i] = -1;
163 	}
164 	bzero(preauth_addrs, sizeof(preauth_addrs));
165 
166 	/* Set up the listening sockets */
167 	listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
168 	if (listensockcount == 0)
169 	{
170 		dropbear_exit("No listening ports available.");
171 	}
172 
173 	/* incoming connection select loop */
174 	for(;;) {
175 
176 		FD_ZERO(&fds);
177 
178 		seltimeout.tv_sec = 60;
179 		seltimeout.tv_usec = 0;
180 
181 		/* listening sockets */
182 		for (i = 0; i < listensockcount; i++) {
183 			FD_SET(listensocks[i], &fds);
184 		}
185 
186 		/* pre-authentication clients */
187 		for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
188 			if (childpipes[i] >= 0) {
189 				FD_SET(childpipes[i], &fds);
190 				maxsock = MAX(maxsock, childpipes[i]);
191 			}
192 		}
193 
194 		val = select(maxsock+1, &fds, NULL, NULL, &seltimeout);
195 
196 		if (exitflag) {
197 			unlink(svr_opts.pidfile);
198 			dropbear_exit("Terminated by signal");
199 		}
200 
201 		if (val == 0) {
202 			/* timeout reached */
203 			continue;
204 		}
205 
206 		if (val < 0) {
207 			if (errno == EINTR) {
208 				continue;
209 			}
210 			dropbear_exit("Listening socket error");
211 		}
212 
213 		/* close fds which have been authed or closed - svr-auth.c handles
214 		 * closing the auth sockets on success */
215 		for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
216 			if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) {
217 				m_close(childpipes[i]);
218 				childpipes[i] = -1;
219 				m_free(preauth_addrs[i]);
220 			}
221 		}
222 
223 		/* handle each socket which has something to say */
224 		for (i = 0; i < listensockcount; i++) {
225 
226 			struct sockaddr_storage remoteaddr;
227 			socklen_t remoteaddrlen = 0;
228 			size_t num_unauthed_for_addr = 0;
229 			size_t num_unauthed_total = 0;
230 			char * remote_addr_str = NULL;
231 			pid_t fork_ret = 0;
232 			size_t conn_idx = 0;
233 
234 			if (!FD_ISSET(listensocks[i], &fds))
235 				continue;
236 
237 			remoteaddrlen = sizeof(remoteaddr);
238 			childsock = accept(listensocks[i],
239 					(struct sockaddr*)&remoteaddr, &remoteaddrlen);
240 
241 			if (childsock < 0) {
242 				/* accept failed */
243 				continue;
244 			}
245 
246 			/* Limit the number of unauthenticated connections per IP */
247 			remote_addr_str = getaddrstring(&remoteaddr, 0);
248 
249 			num_unauthed_for_addr = 0;
250 			num_unauthed_total = 0;
251 			for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
252 				if (childpipes[j] >= 0) {
253 					num_unauthed_total++;
254 					if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) {
255 						num_unauthed_for_addr++;
256 					}
257 				} else {
258 					/* a free slot */
259 					conn_idx = j;
260 				}
261 			}
262 
263 			if (num_unauthed_total >= MAX_UNAUTH_CLIENTS
264 					|| num_unauthed_for_addr >= MAX_UNAUTH_PER_IP) {
265 				goto out;
266 			}
267 
268 			if (pipe(childpipe) < 0) {
269 				TRACE(("error creating child pipe"))
270 				goto out;
271 			}
272 
273 			fork_ret = fork();
274 			if (fork_ret < 0) {
275 				dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno));
276 				goto out;
277 
278 			} else if (fork_ret > 0) {
279 
280 				/* parent */
281 				childpipes[conn_idx] = childpipe[0];
282 				m_close(childpipe[1]);
283 				preauth_addrs[conn_idx] = remote_addr_str;
284 				remote_addr_str = NULL;
285 
286 			} else {
287 
288 				/* child */
289 				char * addrstring = NULL;
290 #ifdef DEBUG_FORKGPROF
291 				extern void _start(void), etext(void);
292 				monstartup((u_long)&_start, (u_long)&etext);
293 #endif /* DEBUG_FORKGPROF */
294 
295 				m_free(remote_addr_str);
296 				addrstring = getaddrstring(&remoteaddr, 1);
297 				dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
298 
299 				if (setsid() < 0) {
300 					dropbear_exit("setsid: %s", strerror(errno));
301 				}
302 
303 				/* make sure we close sockets */
304 				for (i = 0; i < listensockcount; i++) {
305 					m_close(listensocks[i]);
306 				}
307 
308 				m_close(childpipe[0]);
309 
310 				/* start the session */
311 				svr_session(childsock, childpipe[1],
312 								getaddrhostname(&remoteaddr),
313 								addrstring);
314 				/* don't return */
315 				dropbear_assert(0);
316 			}
317 
318 out:
319 			/* This section is important for the parent too */
320 			m_close(childsock);
321 			if (remote_addr_str) {
322 				m_free(remote_addr_str);
323 			}
324 		}
325 	} /* for(;;) loop */
326 
327 	/* don't reach here */
328 }
329 #endif /* NON_INETD_MODE */
330 
331 
332 /* catch + reap zombie children */
sigchld_handler(int UNUSED (unused))333 static void sigchld_handler(int UNUSED(unused)) {
334 	struct sigaction sa_chld;
335 
336 	while(waitpid(-1, NULL, WNOHANG) > 0);
337 
338 	sa_chld.sa_handler = sigchld_handler;
339 	sa_chld.sa_flags = SA_NOCLDSTOP;
340 	if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
341 		dropbear_exit("signal() error");
342 	}
343 }
344 
345 /* catch any segvs */
sigsegv_handler(int UNUSED (unused))346 static void sigsegv_handler(int UNUSED(unused)) {
347 	fprintf(stderr, "Aiee, segfault! You should probably report "
348 			"this as a bug to the developer\n");
349 	exit(EXIT_FAILURE);
350 }
351 
352 /* catch ctrl-c or sigterm */
sigintterm_handler(int UNUSED (unused))353 static void sigintterm_handler(int UNUSED(unused)) {
354 
355 	exitflag = 1;
356 }
357 
358 /* Things used by inetd and non-inetd modes */
commonsetup()359 static void commonsetup() {
360 
361 	struct sigaction sa_chld;
362 #ifndef DISABLE_SYSLOG
363 	if (svr_opts.usingsyslog) {
364 		startsyslog();
365 	}
366 #endif
367 
368 	/* set up cleanup handler */
369 	if (signal(SIGINT, sigintterm_handler) == SIG_ERR ||
370 #ifndef DEBUG_VALGRIND
371 		signal(SIGTERM, sigintterm_handler) == SIG_ERR ||
372 #endif
373 		signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
374 		dropbear_exit("signal() error");
375 	}
376 
377 	/* catch and reap zombie children */
378 	sa_chld.sa_handler = sigchld_handler;
379 	sa_chld.sa_flags = SA_NOCLDSTOP;
380 	if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
381 		dropbear_exit("signal() error");
382 	}
383 	if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
384 		dropbear_exit("signal() error");
385 	}
386 
387 	/* Now we can setup the hostkeys - needs to be after logging is on,
388 	 * otherwise we might end up blatting error messages to the socket */
389 	loadhostkeys();
390 
391     seedrandom();
392 }
393 
394 /* Set up listening sockets for all the requested ports */
listensockets(int * sock,size_t sockcount,int * maxfd)395 static size_t listensockets(int *sock, size_t sockcount, int *maxfd) {
396 
397 	unsigned int i;
398 	char* errstring = NULL;
399 	size_t sockpos = 0;
400 	int nsock;
401 
402 	TRACE(("listensockets: %d to try\n", svr_opts.portcount))
403 
404 	for (i = 0; i < svr_opts.portcount; i++) {
405 
406 		TRACE(("listening on '%s:%s'", svr_opts.addresses[i], svr_opts.ports[i]))
407 
408 		nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &sock[sockpos],
409 				sockcount - sockpos,
410 				&errstring, maxfd);
411 
412 		if (nsock < 0) {
413 			dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
414 							svr_opts.ports[i], errstring);
415 			m_free(errstring);
416 			continue;
417 		}
418 
419 		sockpos += nsock;
420 
421 	}
422 	return sockpos;
423 }
424