Mercurial > dropbear
comparison svr-main.c @ 399:a707e6148060
merge of '5fdf69ca60d1683cdd9f4c2595134bed26394834'
and '6b61c50f4cf888bea302ac8fcf5dbb573b443251'
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 03 Feb 2007 08:20:34 +0000 |
parents | b66a00272a90 |
children | 1afa503e33f5 |
comparison
equal
deleted
inserted
replaced
394:17d097fc111c | 399:a707e6148060 |
---|---|
1 /* | 1 /* |
2 * Dropbear - a SSH2 server | 2 * Dropbear - a SSH2 server |
3 * | 3 * |
4 * Copyright (c) 2002,2003 Matt Johnston | 4 * Copyright (c) 2002-2006 Matt Johnston |
5 * All rights reserved. | 5 * All rights reserved. |
6 * | 6 * |
7 * Permission is hereby granted, free of charge, to any person obtaining a copy | 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 | 8 * of this software and associated documentation files (the "Software"), to deal |
9 * in the Software without restriction, including without limitation the rights | 9 * in the Software without restriction, including without limitation the rights |
26 #include "dbutil.h" | 26 #include "dbutil.h" |
27 #include "session.h" | 27 #include "session.h" |
28 #include "buffer.h" | 28 #include "buffer.h" |
29 #include "signkey.h" | 29 #include "signkey.h" |
30 #include "runopts.h" | 30 #include "runopts.h" |
31 | 31 #include "random.h" |
32 static int listensockets(int *sock, int sockcount, int *maxfd); | 32 |
33 static size_t listensockets(int *sock, size_t sockcount, int *maxfd); | |
33 static void sigchld_handler(int dummy); | 34 static void sigchld_handler(int dummy); |
34 static void sigsegv_handler(int); | 35 static void sigsegv_handler(int); |
35 static void sigintterm_handler(int fish); | 36 static void sigintterm_handler(int fish); |
36 #ifdef INETD_MODE | 37 #ifdef INETD_MODE |
37 static void main_inetd(); | 38 static void main_inetd(); |
39 #ifdef NON_INETD_MODE | 40 #ifdef NON_INETD_MODE |
40 static void main_noinetd(); | 41 static void main_noinetd(); |
41 #endif | 42 #endif |
42 static void commonsetup(); | 43 static void commonsetup(); |
43 | 44 |
44 static int childpipes[MAX_UNAUTH_CLIENTS]; | |
45 | |
46 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) | 45 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) |
47 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) | 46 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) |
48 int dropbear_main(int argc, char ** argv) | 47 int dropbear_main(int argc, char ** argv) |
49 #else | 48 #else |
50 int main(int argc, char ** argv) | 49 int main(int argc, char ** argv) |
51 #endif | 50 #endif |
52 { | 51 { |
53 | |
54 | |
55 _dropbear_exit = svr_dropbear_exit; | 52 _dropbear_exit = svr_dropbear_exit; |
56 _dropbear_log = svr_dropbear_log; | 53 _dropbear_log = svr_dropbear_log; |
57 | 54 |
58 /* get commandline options */ | 55 /* get commandline options */ |
59 svr_getopts(argc, argv); | 56 svr_getopts(argc, argv); |
78 | 75 |
79 #ifdef INETD_MODE | 76 #ifdef INETD_MODE |
80 static void main_inetd() { | 77 static void main_inetd() { |
81 | 78 |
82 struct sockaddr_storage remoteaddr; | 79 struct sockaddr_storage remoteaddr; |
83 int remoteaddrlen; | 80 socklen_t remoteaddrlen; |
84 char * addrstring = NULL; | 81 char * addrstring = NULL; |
85 | 82 |
86 /* Set up handlers, syslog */ | 83 /* Set up handlers, syslog, seed random */ |
87 commonsetup(); | 84 commonsetup(); |
88 | 85 |
89 remoteaddrlen = sizeof(remoteaddr); | 86 remoteaddrlen = sizeof(remoteaddr); |
90 if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) { | 87 if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) { |
91 dropbear_exit("Unable to getpeername: %s", strerror(errno)); | 88 dropbear_exit("Unable to getpeername: %s", strerror(errno)); |
114 fd_set fds; | 111 fd_set fds; |
115 struct timeval seltimeout; | 112 struct timeval seltimeout; |
116 unsigned int i, j; | 113 unsigned int i, j; |
117 int val; | 114 int val; |
118 int maxsock = -1; | 115 int maxsock = -1; |
119 struct sockaddr_storage remoteaddr; | |
120 int remoteaddrlen; | |
121 int listensocks[MAX_LISTEN_ADDR]; | 116 int listensocks[MAX_LISTEN_ADDR]; |
122 int listensockcount = 0; | 117 size_t listensockcount = 0; |
123 FILE *pidfile = NULL; | 118 FILE *pidfile = NULL; |
124 | 119 |
120 int childpipes[MAX_UNAUTH_CLIENTS]; | |
121 char * preauth_addrs[MAX_UNAUTH_CLIENTS]; | |
122 | |
125 int childsock; | 123 int childsock; |
126 pid_t childpid; | |
127 int childpipe[2]; | 124 int childpipe[2]; |
125 | |
126 // Note: commonsetup() must happen before we daemon()ise. Otherwise | |
127 // daemon() will chdir("/"), and we won't be able to find local-dir hostkeys. | |
128 commonsetup(); | |
128 | 129 |
129 /* fork */ | 130 /* fork */ |
130 if (svr_opts.forkbg) { | 131 if (svr_opts.forkbg) { |
131 int closefds = 0; | 132 int closefds = 0; |
132 #ifndef DEBUG_TRACE | 133 #ifndef DEBUG_TRACE |
137 if (daemon(0, closefds) < 0) { | 138 if (daemon(0, closefds) < 0) { |
138 dropbear_exit("Failed to daemonize: %s", strerror(errno)); | 139 dropbear_exit("Failed to daemonize: %s", strerror(errno)); |
139 } | 140 } |
140 } | 141 } |
141 | 142 |
142 commonsetup(); | |
143 | |
144 | |
145 /* should be done after syslog is working */ | 143 /* should be done after syslog is working */ |
146 if (svr_opts.forkbg) { | 144 if (svr_opts.forkbg) { |
147 dropbear_log(LOG_INFO, "Running in background"); | 145 dropbear_log(LOG_INFO, "Running in background"); |
148 } else { | 146 } else { |
149 dropbear_log(LOG_INFO, "Not forking"); | 147 dropbear_log(LOG_INFO, "Not forking"); |
150 } | 148 } |
151 | 149 |
152 /* create a PID file so that we can be killed easily */ | 150 /* create a PID file so that we can be killed easily */ |
153 pidfile = fopen(DROPBEAR_PIDFILE, "w"); | 151 pidfile = fopen(svr_opts.pidfile, "w"); |
154 if (pidfile) { | 152 if (pidfile) { |
155 fprintf(pidfile, "%d\n", getpid()); | 153 fprintf(pidfile, "%d\n", getpid()); |
156 fclose(pidfile); | 154 fclose(pidfile); |
157 } | 155 } |
158 | 156 |
159 /* sockets to identify pre-authenticated clients */ | 157 /* sockets to identify pre-authenticated clients */ |
160 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 158 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
161 childpipes[i] = -1; | 159 childpipes[i] = -1; |
162 } | 160 } |
161 bzero(preauth_addrs, sizeof(preauth_addrs)); | |
163 | 162 |
164 /* Set up the listening sockets */ | 163 /* Set up the listening sockets */ |
165 /* XXX XXX ports */ | |
166 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); | 164 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); |
167 if (listensockcount < 0) { | 165 if (listensockcount == 0) |
166 { | |
168 dropbear_exit("No listening ports available."); | 167 dropbear_exit("No listening ports available."); |
169 } | 168 } |
170 | 169 |
171 /* incoming connection select loop */ | 170 /* incoming connection select loop */ |
172 for(;;) { | 171 for(;;) { |
175 | 174 |
176 seltimeout.tv_sec = 60; | 175 seltimeout.tv_sec = 60; |
177 seltimeout.tv_usec = 0; | 176 seltimeout.tv_usec = 0; |
178 | 177 |
179 /* listening sockets */ | 178 /* listening sockets */ |
180 for (i = 0; i < (unsigned int)listensockcount; i++) { | 179 for (i = 0; i < listensockcount; i++) { |
181 FD_SET(listensocks[i], &fds); | 180 FD_SET(listensocks[i], &fds); |
182 } | 181 } |
183 | 182 |
184 /* pre-authentication clients */ | 183 /* pre-authentication clients */ |
185 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 184 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
190 } | 189 } |
191 | 190 |
192 val = select(maxsock+1, &fds, NULL, NULL, &seltimeout); | 191 val = select(maxsock+1, &fds, NULL, NULL, &seltimeout); |
193 | 192 |
194 if (exitflag) { | 193 if (exitflag) { |
195 unlink(DROPBEAR_PIDFILE); | 194 unlink(svr_opts.pidfile); |
196 dropbear_exit("Terminated by signal"); | 195 dropbear_exit("Terminated by signal"); |
197 } | 196 } |
198 | 197 |
199 if (val == 0) { | 198 if (val == 0) { |
200 /* timeout reached */ | 199 /* timeout reached */ |
206 continue; | 205 continue; |
207 } | 206 } |
208 dropbear_exit("Listening socket error"); | 207 dropbear_exit("Listening socket error"); |
209 } | 208 } |
210 | 209 |
211 /* close fds which have been authed or closed - auth.c handles | 210 /* close fds which have been authed or closed - svr-auth.c handles |
212 * closing the auth sockets on success */ | 211 * closing the auth sockets on success */ |
213 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 212 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
214 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { | 213 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { |
215 close(childpipes[i]); | 214 m_close(childpipes[i]); |
216 childpipes[i] = -1; | 215 childpipes[i] = -1; |
216 m_free(preauth_addrs[i]); | |
217 } | 217 } |
218 } | 218 } |
219 | 219 |
220 /* handle each socket which has something to say */ | 220 /* handle each socket which has something to say */ |
221 for (i = 0; i < (unsigned int)listensockcount; i++) { | 221 for (i = 0; i < listensockcount; i++) { |
222 | |
223 struct sockaddr_storage remoteaddr; | |
224 socklen_t remoteaddrlen = 0; | |
225 size_t num_unauthed_for_addr = 0; | |
226 size_t num_unauthed_total = 0; | |
227 char * remote_addr_str = NULL; | |
228 pid_t fork_ret = 0; | |
229 size_t conn_idx = 0; | |
230 | |
222 if (!FD_ISSET(listensocks[i], &fds)) | 231 if (!FD_ISSET(listensocks[i], &fds)) |
223 continue; | 232 continue; |
224 | 233 |
225 remoteaddrlen = sizeof(remoteaddr); | 234 remoteaddrlen = sizeof(remoteaddr); |
226 childsock = accept(listensocks[i], | 235 childsock = accept(listensocks[i], |
229 if (childsock < 0) { | 238 if (childsock < 0) { |
230 /* accept failed */ | 239 /* accept failed */ |
231 continue; | 240 continue; |
232 } | 241 } |
233 | 242 |
234 /* check for max number of connections not authorised */ | 243 /* Limit the number of unauthenticated connections per IP */ |
244 remote_addr_str = getaddrstring(&remoteaddr, 0); | |
245 | |
246 num_unauthed_for_addr = 0; | |
247 num_unauthed_total = 0; | |
235 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { | 248 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { |
236 if (childpipes[j] < 0) { | 249 if (childpipes[j] >= 0) { |
237 break; | 250 num_unauthed_total++; |
251 if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) { | |
252 num_unauthed_for_addr++; | |
253 } | |
254 } else { | |
255 /* a free slot */ | |
256 conn_idx = j; | |
238 } | 257 } |
239 } | 258 } |
240 | 259 |
241 if (j == MAX_UNAUTH_CLIENTS) { | 260 if (num_unauthed_total >= MAX_UNAUTH_CLIENTS |
242 /* no free connections */ | 261 || num_unauthed_for_addr >= MAX_UNAUTH_PER_IP) { |
243 /* TODO - possibly log, though this would be an easy way | 262 goto out; |
244 * to fill logs/disk */ | |
245 close(childsock); | |
246 continue; | |
247 } | 263 } |
248 | 264 |
249 if (pipe(childpipe) < 0) { | 265 if (pipe(childpipe) < 0) { |
250 TRACE(("error creating child pipe")) | 266 TRACE(("error creating child pipe")) |
251 close(childsock); | 267 goto out; |
252 continue; | 268 } |
253 } | 269 |
254 | 270 fork_ret = fork(); |
255 if ((childpid = fork()) == 0) { | 271 if (fork_ret < 0) { |
272 dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno)); | |
273 goto out; | |
274 | |
275 } else if (fork_ret > 0) { | |
276 | |
277 /* parent */ | |
278 childpipes[conn_idx] = childpipe[0]; | |
279 m_close(childpipe[1]); | |
280 preauth_addrs[conn_idx] = remote_addr_str; | |
281 remote_addr_str = NULL; | |
282 | |
283 } else { | |
256 | 284 |
257 /* child */ | 285 /* child */ |
258 char * addrstring = NULL; | 286 char * addrstring = NULL; |
259 #ifdef DEBUG_FORKGPROF | 287 #ifdef DEBUG_FORKGPROF |
260 extern void _start(void), etext(void); | 288 extern void _start(void), etext(void); |
261 monstartup((u_long)&_start, (u_long)&etext); | 289 monstartup((u_long)&_start, (u_long)&etext); |
262 #endif /* DEBUG_FORKGPROF */ | 290 #endif /* DEBUG_FORKGPROF */ |
263 | 291 |
292 m_free(remote_addr_str); | |
264 addrstring = getaddrstring(&remoteaddr, 1); | 293 addrstring = getaddrstring(&remoteaddr, 1); |
265 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); | 294 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); |
266 | 295 |
267 if (setsid() < 0) { | 296 if (setsid() < 0) { |
268 dropbear_exit("setsid: %s", strerror(errno)); | 297 dropbear_exit("setsid: %s", strerror(errno)); |
269 } | 298 } |
270 | 299 |
271 /* make sure we close sockets */ | 300 /* make sure we close sockets */ |
272 for (i = 0; i < (unsigned int)listensockcount; i++) { | 301 for (i = 0; i < listensockcount; i++) { |
273 if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { | 302 m_close(listensocks[i]); |
274 dropbear_exit("Couldn't close socket"); | |
275 } | |
276 } | 303 } |
277 | 304 |
278 if (m_close(childpipe[0]) == DROPBEAR_FAILURE) { | 305 m_close(childpipe[0]); |
279 dropbear_exit("Couldn't close socket"); | |
280 } | |
281 | 306 |
282 /* start the session */ | 307 /* start the session */ |
283 svr_session(childsock, childpipe[1], | 308 svr_session(childsock, childpipe[1], |
284 getaddrhostname(&remoteaddr), | 309 getaddrhostname(&remoteaddr), |
285 addrstring); | 310 addrstring); |
286 /* don't return */ | 311 /* don't return */ |
287 dropbear_assert(0); | 312 dropbear_assert(0); |
288 } | 313 } |
289 | 314 |
290 /* parent */ | 315 out: |
291 childpipes[j] = childpipe[0]; | 316 /* This section is important for the parent too */ |
292 if (m_close(childpipe[1]) == DROPBEAR_FAILURE | 317 m_close(childsock); |
293 || m_close(childsock) == DROPBEAR_FAILURE) { | 318 if (remote_addr_str) { |
294 dropbear_exit("Couldn't close socket"); | 319 m_free(remote_addr_str); |
295 } | 320 } |
296 } | 321 } |
297 } /* for(;;) loop */ | 322 } /* for(;;) loop */ |
298 | 323 |
299 /* don't reach here */ | 324 /* don't reach here */ |
357 } | 382 } |
358 | 383 |
359 /* Now we can setup the hostkeys - needs to be after logging is on, | 384 /* Now we can setup the hostkeys - needs to be after logging is on, |
360 * otherwise we might end up blatting error messages to the socket */ | 385 * otherwise we might end up blatting error messages to the socket */ |
361 loadhostkeys(); | 386 loadhostkeys(); |
387 | |
388 seedrandom(); | |
362 } | 389 } |
363 | 390 |
364 /* Set up listening sockets for all the requested ports */ | 391 /* Set up listening sockets for all the requested ports */ |
365 static int listensockets(int *sock, int sockcount, int *maxfd) { | 392 static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { |
366 | 393 |
367 unsigned int i; | 394 unsigned int i; |
368 char* errstring = NULL; | 395 char* errstring = NULL; |
369 unsigned int sockpos = 0; | 396 size_t sockpos = 0; |
370 int nsock; | 397 int nsock; |
371 | 398 |
372 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) | 399 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) |
373 | 400 |
374 for (i = 0; i < svr_opts.portcount; i++) { | 401 for (i = 0; i < svr_opts.portcount; i++) { |