Mercurial > dropbear
comparison svr-main.c @ 293:9d110777f345 contrib-blacklist
propagate from branch 'au.asn.ucc.matt.dropbear' (head 7ad1775ed65e75dbece27fe6b65bf1a234db386a)
to branch 'au.asn.ucc.matt.dropbear.contrib.blacklist' (head 1d86a4f0a401cc68c2670d821a2f6366c37af143)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 10 Mar 2006 06:31:29 +0000 |
parents | c07de41b53d7 94ee16f5b8a8 |
children |
comparison
equal
deleted
inserted
replaced
247:c07de41b53d7 | 293:9d110777f345 |
---|---|
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 |
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 #include "blacklist.h" | 31 #include "blacklist.h" |
32 | 32 |
33 static int listensockets(int *sock, int sockcount, int *maxfd); | 33 static size_t listensockets(int *sock, size_t sockcount, int *maxfd); |
34 static void sigchld_handler(int dummy); | 34 static void sigchld_handler(int dummy); |
35 static void sigsegv_handler(int); | 35 static void sigsegv_handler(int); |
36 static void sigintterm_handler(int fish); | 36 static void sigintterm_handler(int fish); |
37 #ifdef INETD_MODE | 37 #ifdef INETD_MODE |
38 static void main_inetd(); | 38 static void main_inetd(); |
40 #ifdef NON_INETD_MODE | 40 #ifdef NON_INETD_MODE |
41 static void main_noinetd(); | 41 static void main_noinetd(); |
42 #endif | 42 #endif |
43 static void commonsetup(); | 43 static void commonsetup(); |
44 | 44 |
45 static int childpipes[MAX_UNAUTH_CLIENTS]; | |
46 | |
47 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) | 45 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) |
48 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) | 46 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) |
49 int dropbear_main(int argc, char ** argv) | 47 int dropbear_main(int argc, char ** argv) |
50 #else | 48 #else |
51 int main(int argc, char ** argv) | 49 int main(int argc, char ** argv) |
52 #endif | 50 #endif |
53 { | 51 { |
54 | |
55 | |
56 _dropbear_exit = svr_dropbear_exit; | 52 _dropbear_exit = svr_dropbear_exit; |
57 _dropbear_log = svr_dropbear_log; | 53 _dropbear_log = svr_dropbear_log; |
58 | 54 |
59 /* get commandline options */ | 55 /* get commandline options */ |
60 svr_getopts(argc, argv); | 56 svr_getopts(argc, argv); |
79 | 75 |
80 #ifdef INETD_MODE | 76 #ifdef INETD_MODE |
81 static void main_inetd() { | 77 static void main_inetd() { |
82 | 78 |
83 struct sockaddr_storage remoteaddr; | 79 struct sockaddr_storage remoteaddr; |
84 int remoteaddrlen; | 80 socklen_t remoteaddrlen; |
85 char * addrstring = NULL; | 81 char * addrstring = NULL; |
86 | 82 |
87 /* Set up handlers, syslog */ | 83 /* Set up handlers, syslog, seed random */ |
88 commonsetup(); | 84 commonsetup(); |
89 | 85 |
90 remoteaddrlen = sizeof(remoteaddr); | 86 remoteaddrlen = sizeof(remoteaddr); |
91 if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) { | 87 if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) { |
92 dropbear_exit("Unable to getpeername: %s", strerror(errno)); | 88 dropbear_exit("Unable to getpeername: %s", strerror(errno)); |
115 fd_set fds; | 111 fd_set fds; |
116 struct timeval seltimeout; | 112 struct timeval seltimeout; |
117 unsigned int i, j; | 113 unsigned int i, j; |
118 int val; | 114 int val; |
119 int maxsock = -1; | 115 int maxsock = -1; |
120 struct sockaddr_storage remoteaddr; | |
121 int remoteaddrlen; | |
122 int listensocks[MAX_LISTEN_ADDR]; | 116 int listensocks[MAX_LISTEN_ADDR]; |
123 int listensockcount = 0; | 117 size_t listensockcount = 0; |
124 FILE *pidfile = NULL; | 118 FILE *pidfile = NULL; |
125 | 119 |
120 int childpipes[MAX_UNAUTH_CLIENTS]; | |
121 char * preauth_addrs[MAX_UNAUTH_CLIENTS]; | |
122 | |
126 int childsock; | 123 int childsock; |
127 pid_t childpid; | |
128 int childpipe[2]; | 124 int childpipe[2]; |
129 | 125 |
130 /* fork */ | 126 /* fork */ |
131 if (svr_opts.forkbg) { | 127 if (svr_opts.forkbg) { |
132 int closefds = 0; | 128 int closefds = 0; |
140 } | 136 } |
141 } | 137 } |
142 | 138 |
143 commonsetup(); | 139 commonsetup(); |
144 | 140 |
145 | |
146 /* should be done after syslog is working */ | 141 /* should be done after syslog is working */ |
147 if (svr_opts.forkbg) { | 142 if (svr_opts.forkbg) { |
148 dropbear_log(LOG_INFO, "Running in background"); | 143 dropbear_log(LOG_INFO, "Running in background"); |
149 } else { | 144 } else { |
150 dropbear_log(LOG_INFO, "Not forking"); | 145 dropbear_log(LOG_INFO, "Not forking"); |
159 | 154 |
160 /* sockets to identify pre-authenticated clients */ | 155 /* sockets to identify pre-authenticated clients */ |
161 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 156 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
162 childpipes[i] = -1; | 157 childpipes[i] = -1; |
163 } | 158 } |
159 bzero(preauth_addrs, sizeof(preauth_addrs)); | |
164 | 160 |
165 /* Set up the listening sockets */ | 161 /* Set up the listening sockets */ |
166 /* XXX XXX ports */ | |
167 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); | 162 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); |
168 if (listensockcount < 0) { | 163 if (listensockcount == 0) |
164 { | |
169 dropbear_exit("No listening ports available."); | 165 dropbear_exit("No listening ports available."); |
170 } | 166 } |
171 | 167 |
172 /* incoming connection select loop */ | 168 /* incoming connection select loop */ |
173 for(;;) { | 169 for(;;) { |
176 | 172 |
177 seltimeout.tv_sec = 60; | 173 seltimeout.tv_sec = 60; |
178 seltimeout.tv_usec = 0; | 174 seltimeout.tv_usec = 0; |
179 | 175 |
180 /* listening sockets */ | 176 /* listening sockets */ |
181 for (i = 0; i < (unsigned int)listensockcount; i++) { | 177 for (i = 0; i < listensockcount; i++) { |
182 FD_SET(listensocks[i], &fds); | 178 FD_SET(listensocks[i], &fds); |
183 } | 179 } |
184 | 180 |
185 /* pre-authentication clients */ | 181 /* pre-authentication clients */ |
186 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 182 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
207 continue; | 203 continue; |
208 } | 204 } |
209 dropbear_exit("Listening socket error"); | 205 dropbear_exit("Listening socket error"); |
210 } | 206 } |
211 | 207 |
212 /* close fds which have been authed or closed - auth.c handles | 208 /* close fds which have been authed or closed - svr-auth.c handles |
213 * closing the auth sockets on success */ | 209 * closing the auth sockets on success */ |
214 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 210 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
215 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { | 211 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { |
216 close(childpipes[i]); | 212 m_close(childpipes[i]); |
217 childpipes[i] = -1; | 213 childpipes[i] = -1; |
214 m_free(preauth_addrs[i]); | |
218 } | 215 } |
219 } | 216 } |
220 | 217 |
221 /* handle each socket which has something to say */ | 218 /* handle each socket which has something to say */ |
222 for (i = 0; i < (unsigned int)listensockcount; i++) { | 219 for (i = 0; i < listensockcount; i++) { |
220 | |
221 struct sockaddr_storage remoteaddr; | |
222 socklen_t remoteaddrlen = 0; | |
223 size_t num_unauthed_for_addr = 0; | |
224 size_t num_unauthed_total = 0; | |
225 char * remote_addr_str = NULL; | |
226 pid_t fork_ret = 0; | |
227 size_t conn_idx = 0; | |
228 | |
223 if (!FD_ISSET(listensocks[i], &fds)) | 229 if (!FD_ISSET(listensocks[i], &fds)) |
224 continue; | 230 continue; |
225 | 231 |
226 remoteaddrlen = sizeof(remoteaddr); | 232 remoteaddrlen = sizeof(remoteaddr); |
227 childsock = accept(listensocks[i], | 233 childsock = accept(listensocks[i], |
230 if (childsock < 0) { | 236 if (childsock < 0) { |
231 /* accept failed */ | 237 /* accept failed */ |
232 continue; | 238 continue; |
233 } | 239 } |
234 | 240 |
235 /* check for max number of connections not authorised */ | 241 /* Limit the number of unauthenticated connections per IP */ |
242 remote_addr_str = getaddrstring(&remoteaddr, 0); | |
243 | |
244 num_unauthed_for_addr = 0; | |
245 num_unauthed_total = 0; | |
236 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { | 246 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { |
237 if (childpipes[j] < 0) { | 247 if (childpipes[j] >= 0) { |
238 break; | 248 num_unauthed_total++; |
249 if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) { | |
250 num_unauthed_for_addr++; | |
251 } | |
252 } else { | |
253 /* a free slot */ | |
254 conn_idx = j; | |
239 } | 255 } |
240 } | 256 } |
241 | 257 |
242 if (is_blacklisted(getaddrstring(&remoteaddr, 0)) == 1) { | 258 if (is_blacklisted(getaddrstring(&remoteaddr, 0)) == 1) { |
243 close(childsock); | 259 close(childsock); |
244 continue; | 260 continue; |
245 } | 261 } |
246 | 262 |
247 if (j == MAX_UNAUTH_CLIENTS) { | 263 if (num_unauthed_total >= MAX_UNAUTH_CLIENTS |
248 /* no free connections */ | 264 || num_unauthed_for_addr >= MAX_UNAUTH_PER_IP) { |
249 /* TODO - possibly log, though this would be an easy way | 265 goto out; |
250 * to fill logs/disk */ | |
251 close(childsock); | |
252 continue; | |
253 } | 266 } |
254 | 267 |
255 if (pipe(childpipe) < 0) { | 268 if (pipe(childpipe) < 0) { |
256 TRACE(("error creating child pipe")) | 269 TRACE(("error creating child pipe")) |
257 close(childsock); | 270 goto out; |
258 continue; | 271 } |
259 } | 272 |
260 | 273 fork_ret = fork(); |
261 if ((childpid = fork()) == 0) { | 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 { | |
262 | 287 |
263 /* child */ | 288 /* child */ |
264 char * addrstring = NULL; | 289 char * addrstring = NULL; |
265 #ifdef DEBUG_FORKGPROF | 290 #ifdef DEBUG_FORKGPROF |
266 extern void _start(void), etext(void); | 291 extern void _start(void), etext(void); |
267 monstartup((u_long)&_start, (u_long)&etext); | 292 monstartup((u_long)&_start, (u_long)&etext); |
268 #endif /* DEBUG_FORKGPROF */ | 293 #endif /* DEBUG_FORKGPROF */ |
269 | 294 |
295 m_free(remote_addr_str); | |
270 addrstring = getaddrstring(&remoteaddr, 1); | 296 addrstring = getaddrstring(&remoteaddr, 1); |
271 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); | 297 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); |
272 | 298 |
273 if (setsid() < 0) { | 299 if (setsid() < 0) { |
274 dropbear_exit("setsid: %s", strerror(errno)); | 300 dropbear_exit("setsid: %s", strerror(errno)); |
275 } | 301 } |
276 | 302 |
277 /* make sure we close sockets */ | 303 /* make sure we close sockets */ |
278 for (i = 0; i < (unsigned int)listensockcount; i++) { | 304 for (i = 0; i < listensockcount; i++) { |
279 if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { | 305 m_close(listensocks[i]); |
280 dropbear_exit("Couldn't close socket"); | |
281 } | |
282 } | 306 } |
283 | 307 |
284 if (m_close(childpipe[0]) == DROPBEAR_FAILURE) { | 308 m_close(childpipe[0]); |
285 dropbear_exit("Couldn't close socket"); | |
286 } | |
287 | 309 |
288 /* start the session */ | 310 /* start the session */ |
289 svr_session(childsock, childpipe[1], | 311 svr_session(childsock, childpipe[1], |
290 getaddrhostname(&remoteaddr), | 312 getaddrhostname(&remoteaddr), |
291 addrstring); | 313 addrstring); |
292 /* don't return */ | 314 /* don't return */ |
293 dropbear_assert(0); | 315 dropbear_assert(0); |
294 } | 316 } |
295 | 317 |
296 /* parent */ | 318 out: |
297 childpipes[j] = childpipe[0]; | 319 /* This section is important for the parent too */ |
298 if (m_close(childpipe[1]) == DROPBEAR_FAILURE | 320 m_close(childsock); |
299 || m_close(childsock) == DROPBEAR_FAILURE) { | 321 if (remote_addr_str) { |
300 dropbear_exit("Couldn't close socket"); | 322 m_free(remote_addr_str); |
301 } | 323 } |
302 } | 324 } |
303 } /* for(;;) loop */ | 325 } /* for(;;) loop */ |
304 | 326 |
305 /* don't reach here */ | 327 /* don't reach here */ |
363 } | 385 } |
364 | 386 |
365 /* Now we can setup the hostkeys - needs to be after logging is on, | 387 /* Now we can setup the hostkeys - needs to be after logging is on, |
366 * otherwise we might end up blatting error messages to the socket */ | 388 * otherwise we might end up blatting error messages to the socket */ |
367 loadhostkeys(); | 389 loadhostkeys(); |
390 | |
391 seedrandom(); | |
368 } | 392 } |
369 | 393 |
370 /* Set up listening sockets for all the requested ports */ | 394 /* Set up listening sockets for all the requested ports */ |
371 static int listensockets(int *sock, int sockcount, int *maxfd) { | 395 static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { |
372 | 396 |
373 unsigned int i; | 397 unsigned int i; |
374 char* errstring = NULL; | 398 char* errstring = NULL; |
375 unsigned int sockpos = 0; | 399 size_t sockpos = 0; |
376 int nsock; | 400 int nsock; |
377 | 401 |
378 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) | 402 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) |
379 | 403 |
380 for (i = 0; i < svr_opts.portcount; i++) { | 404 for (i = 0; i < svr_opts.portcount; i++) { |
381 | 405 |
382 TRACE(("listening on '%s'", svr_opts.ports[i])) | 406 TRACE(("listening on '%s'", svr_opts.ports[i])) |
383 | 407 |
384 nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos], | 408 nsock = dropbear_listen("", svr_opts.ports[i], &sock[sockpos], |
385 sockcount - sockpos, | 409 sockcount - sockpos, |
386 &errstring, maxfd); | 410 &errstring, maxfd); |
387 | 411 |
388 if (nsock < 0) { | 412 if (nsock < 0) { |
389 dropbear_log(LOG_WARNING, "Failed listening on '%s': %s", | 413 dropbear_log(LOG_WARNING, "Failed listening on '%s': %s", |