Mercurial > dropbear
comparison svr-main.c @ 277:044bc108b9b3
* Per-IP connection unauthed connection limits
* m_close() exits fatally on failure
* other cleanups
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 08 Mar 2006 12:41:27 +0000 |
parents | 306499676384 |
children | 1f5ec029dfe8 |
comparison
equal
deleted
inserted
replaced
266:e37b160c414c | 277:044bc108b9b3 |
---|---|
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 |
32 static int listensockets(int *sock, int sockcount, int *maxfd); | 32 static size_t listensockets(int *sock, size_t sockcount, int *maxfd); |
33 static void sigchld_handler(int dummy); | 33 static void sigchld_handler(int dummy); |
34 static void sigsegv_handler(int); | 34 static void sigsegv_handler(int); |
35 static void sigintterm_handler(int fish); | 35 static void sigintterm_handler(int fish); |
36 #ifdef INETD_MODE | 36 #ifdef INETD_MODE |
37 static void main_inetd(); | 37 static void main_inetd(); |
39 #ifdef NON_INETD_MODE | 39 #ifdef NON_INETD_MODE |
40 static void main_noinetd(); | 40 static void main_noinetd(); |
41 #endif | 41 #endif |
42 static void commonsetup(); | 42 static void commonsetup(); |
43 | 43 |
44 static int childpipes[MAX_UNAUTH_CLIENTS]; | |
45 | |
46 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) | 44 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) |
47 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) | 45 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) |
48 int dropbear_main(int argc, char ** argv) | 46 int dropbear_main(int argc, char ** argv) |
49 #else | 47 #else |
50 int main(int argc, char ** argv) | 48 int main(int argc, char ** argv) |
78 | 76 |
79 #ifdef INETD_MODE | 77 #ifdef INETD_MODE |
80 static void main_inetd() { | 78 static void main_inetd() { |
81 | 79 |
82 struct sockaddr_storage remoteaddr; | 80 struct sockaddr_storage remoteaddr; |
83 int remoteaddrlen; | 81 socklen_t remoteaddrlen; |
84 char * addrstring = NULL; | 82 char * addrstring = NULL; |
85 | 83 |
86 /* Set up handlers, syslog */ | 84 /* Set up handlers, syslog */ |
87 commonsetup(); | 85 commonsetup(); |
88 | 86 |
114 fd_set fds; | 112 fd_set fds; |
115 struct timeval seltimeout; | 113 struct timeval seltimeout; |
116 unsigned int i, j; | 114 unsigned int i, j; |
117 int val; | 115 int val; |
118 int maxsock = -1; | 116 int maxsock = -1; |
119 struct sockaddr_storage remoteaddr; | |
120 int remoteaddrlen; | |
121 int listensocks[MAX_LISTEN_ADDR]; | 117 int listensocks[MAX_LISTEN_ADDR]; |
122 int listensockcount = 0; | 118 size_t listensockcount = 0; |
123 FILE *pidfile = NULL; | 119 FILE *pidfile = NULL; |
124 | 120 |
121 int childpipes[MAX_UNAUTH_CLIENTS]; | |
122 char * preauth_addrs[MAX_UNAUTH_CLIENTS]; | |
123 | |
125 int childsock; | 124 int childsock; |
126 pid_t childpid; | |
127 int childpipe[2]; | 125 int childpipe[2]; |
128 | 126 |
129 /* fork */ | 127 /* fork */ |
130 if (svr_opts.forkbg) { | 128 if (svr_opts.forkbg) { |
131 int closefds = 0; | 129 int closefds = 0; |
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 */ | 164 /* XXX XXX ports */ |
166 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); | 165 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); |
167 if (listensockcount < 0) { | 166 if (listensockcount == 0) |
167 { | |
168 dropbear_exit("No listening ports available."); | 168 dropbear_exit("No listening ports available."); |
169 } | 169 } |
170 | 170 |
171 /* incoming connection select loop */ | 171 /* incoming connection select loop */ |
172 for(;;) { | 172 for(;;) { |
175 | 175 |
176 seltimeout.tv_sec = 60; | 176 seltimeout.tv_sec = 60; |
177 seltimeout.tv_usec = 0; | 177 seltimeout.tv_usec = 0; |
178 | 178 |
179 /* listening sockets */ | 179 /* listening sockets */ |
180 for (i = 0; i < (unsigned int)listensockcount; i++) { | 180 for (i = 0; i < listensockcount; i++) { |
181 FD_SET(listensocks[i], &fds); | 181 FD_SET(listensocks[i], &fds); |
182 } | 182 } |
183 | 183 |
184 /* pre-authentication clients */ | 184 /* pre-authentication clients */ |
185 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 185 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
206 continue; | 206 continue; |
207 } | 207 } |
208 dropbear_exit("Listening socket error"); | 208 dropbear_exit("Listening socket error"); |
209 } | 209 } |
210 | 210 |
211 /* close fds which have been authed or closed - auth.c handles | 211 /* close fds which have been authed or closed - svr-auth.c handles |
212 * closing the auth sockets on success */ | 212 * closing the auth sockets on success */ |
213 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 213 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
214 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { | 214 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { |
215 close(childpipes[i]); | 215 m_close(childpipes[i]); |
216 childpipes[i] = -1; | 216 childpipes[i] = -1; |
217 m_free(preauth_addrs[i]); | |
217 } | 218 } |
218 } | 219 } |
219 | 220 |
220 /* handle each socket which has something to say */ | 221 /* handle each socket which has something to say */ |
221 for (i = 0; i < (unsigned int)listensockcount; i++) { | 222 for (i = 0; i < listensockcount; i++) { |
223 | |
224 struct sockaddr_storage remoteaddr; | |
225 socklen_t remoteaddrlen = 0; | |
226 size_t num_unauthed_for_addr = 0; | |
227 size_t num_unauthed_total = 0; | |
228 char * remote_addr_str = NULL; | |
229 pid_t fork_ret = 0; | |
230 size_t conn_idx = 0; | |
231 | |
222 if (!FD_ISSET(listensocks[i], &fds)) | 232 if (!FD_ISSET(listensocks[i], &fds)) |
223 continue; | 233 continue; |
224 | 234 |
225 remoteaddrlen = sizeof(remoteaddr); | 235 remoteaddrlen = sizeof(remoteaddr); |
226 childsock = accept(listensocks[i], | 236 childsock = accept(listensocks[i], |
229 if (childsock < 0) { | 239 if (childsock < 0) { |
230 /* accept failed */ | 240 /* accept failed */ |
231 continue; | 241 continue; |
232 } | 242 } |
233 | 243 |
234 /* check for max number of connections not authorised */ | 244 /* Limit the number of unauthenticated connections per IP */ |
245 remote_addr_str = getaddrstring(&remoteaddr, 0); | |
246 | |
247 num_unauthed_for_addr = 0; | |
248 num_unauthed_total = 0; | |
235 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { | 249 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { |
236 if (childpipes[j] < 0) { | 250 if (childpipes[j] >= 0) { |
237 break; | 251 num_unauthed_total++; |
252 if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) { | |
253 num_unauthed_for_addr++; | |
254 } | |
255 } else { | |
256 /* a free slot */ | |
257 conn_idx = j; | |
238 } | 258 } |
239 } | 259 } |
240 | 260 |
241 if (j == MAX_UNAUTH_CLIENTS) { | 261 if (num_unauthed_total >= MAX_UNAUTH_CLIENTS |
242 /* no free connections */ | 262 || num_unauthed_for_addr >= MAX_UNAUTH_PER_IP) { |
243 /* TODO - possibly log, though this would be an easy way | 263 goto out; |
244 * to fill logs/disk */ | |
245 close(childsock); | |
246 continue; | |
247 } | 264 } |
248 | 265 |
249 if (pipe(childpipe) < 0) { | 266 if (pipe(childpipe) < 0) { |
250 TRACE(("error creating child pipe")) | 267 TRACE(("error creating child pipe")) |
251 close(childsock); | 268 goto out; |
252 continue; | 269 } |
253 } | 270 |
254 | 271 fork_ret = fork(); |
255 if ((childpid = fork()) == 0) { | 272 if (fork_ret < 0) { |
273 dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno)); | |
274 goto out; | |
275 | |
276 } else if (fork_ret > 0) { | |
277 | |
278 /* parent */ | |
279 childpipes[conn_idx] = childpipe[0]; | |
280 m_close(childpipe[1]); | |
281 preauth_addrs[conn_idx] = remote_addr_str; | |
282 remote_addr_str = NULL; | |
283 | |
284 } else { | |
256 | 285 |
257 /* child */ | 286 /* child */ |
258 char * addrstring = NULL; | 287 char * addrstring = NULL; |
259 #ifdef DEBUG_FORKGPROF | 288 #ifdef DEBUG_FORKGPROF |
260 extern void _start(void), etext(void); | 289 extern void _start(void), etext(void); |
261 monstartup((u_long)&_start, (u_long)&etext); | 290 monstartup((u_long)&_start, (u_long)&etext); |
262 #endif /* DEBUG_FORKGPROF */ | 291 #endif /* DEBUG_FORKGPROF */ |
263 | 292 |
293 m_free(remote_addr_str); | |
264 addrstring = getaddrstring(&remoteaddr, 1); | 294 addrstring = getaddrstring(&remoteaddr, 1); |
265 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); | 295 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); |
266 | 296 |
267 if (setsid() < 0) { | 297 if (setsid() < 0) { |
268 dropbear_exit("setsid: %s", strerror(errno)); | 298 dropbear_exit("setsid: %s", strerror(errno)); |
269 } | 299 } |
270 | 300 |
271 /* make sure we close sockets */ | 301 /* make sure we close sockets */ |
272 for (i = 0; i < (unsigned int)listensockcount; i++) { | 302 for (i = 0; i < listensockcount; i++) { |
273 if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { | 303 m_close(listensocks[i]); |
274 dropbear_exit("Couldn't close socket"); | |
275 } | |
276 } | 304 } |
277 | 305 |
278 if (m_close(childpipe[0]) == DROPBEAR_FAILURE) { | 306 m_close(childpipe[0]); |
279 dropbear_exit("Couldn't close socket"); | |
280 } | |
281 | 307 |
282 /* start the session */ | 308 /* start the session */ |
283 svr_session(childsock, childpipe[1], | 309 svr_session(childsock, childpipe[1], |
284 getaddrhostname(&remoteaddr), | 310 getaddrhostname(&remoteaddr), |
285 addrstring); | 311 addrstring); |
286 /* don't return */ | 312 /* don't return */ |
287 dropbear_assert(0); | 313 dropbear_assert(0); |
288 } | 314 } |
289 | 315 |
290 /* parent */ | 316 out: |
291 childpipes[j] = childpipe[0]; | 317 /* This section is important for the parent too */ |
292 if (m_close(childpipe[1]) == DROPBEAR_FAILURE | 318 m_close(childsock); |
293 || m_close(childsock) == DROPBEAR_FAILURE) { | 319 if (remote_addr_str) { |
294 dropbear_exit("Couldn't close socket"); | 320 m_free(remote_addr_str); |
295 } | 321 } |
296 } | 322 } |
297 } /* for(;;) loop */ | 323 } /* for(;;) loop */ |
298 | 324 |
299 /* don't reach here */ | 325 /* don't reach here */ |
360 * otherwise we might end up blatting error messages to the socket */ | 386 * otherwise we might end up blatting error messages to the socket */ |
361 loadhostkeys(); | 387 loadhostkeys(); |
362 } | 388 } |
363 | 389 |
364 /* Set up listening sockets for all the requested ports */ | 390 /* Set up listening sockets for all the requested ports */ |
365 static int listensockets(int *sock, int sockcount, int *maxfd) { | 391 static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { |
366 | 392 |
367 unsigned int i; | 393 unsigned int i; |
368 char* errstring = NULL; | 394 char* errstring = NULL; |
369 unsigned int sockpos = 0; | 395 size_t sockpos = 0; |
370 int nsock; | 396 int nsock; |
371 | 397 |
372 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) | 398 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) |
373 | 399 |
374 for (i = 0; i < svr_opts.portcount; i++) { | 400 for (i = 0; i < svr_opts.portcount; i++) { |