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++) {