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
33static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
34static void sigchld_handler(int dummy);
35static void sigsegv_handler(int);
36static void sigintterm_handler(int fish);
37#ifdef INETD_MODE
38static void main_inetd();
39#endif
40#ifdef NON_INETD_MODE
41static void main_noinetd();
42#endif
43static void commonsetup();
44
45#if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI)
46#if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI)
47int dropbear_main(int argc, char ** argv)
48#else
49int 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
79static 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
112void 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
318out:
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 */
333static 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 */
346static 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 */
353static void sigintterm_handler(int UNUSED(unused)) {
354
355	exitflag = 1;
356}
357
358/* Things used by inetd and non-inetd modes */
359static 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 */
395static 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