Mercurial > dropbear
comparison svr-main.c @ 302:973fccb59ea4 ucc-axis-hack
propagate from branch 'au.asn.ucc.matt.dropbear' (head 11034278bd1917bebcbdc69cf53b1891ce9db121)
to branch 'au.asn.ucc.matt.dropbear.ucc-axis-hack' (head 10a1f614fec73d0820c3f61160d9db409b9beb46)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 25 Mar 2006 12:59:58 +0000 |
parents | 740e782679be 7dad470ad4aa |
children | 474c1a700b67 |
comparison
equal
deleted
inserted
replaced
299:740e782679be | 302:973fccb59ea4 |
---|---|
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]; |
128 | 125 |
129 /* fork */ | 126 /* fork */ |
130 if (svr_opts.forkbg) { | 127 if (svr_opts.forkbg) { |
131 int closefds = 0; | 128 int closefds = 0; |
139 } | 136 } |
140 } | 137 } |
141 | 138 |
142 commonsetup(); | 139 commonsetup(); |
143 | 140 |
144 | |
145 /* should be done after syslog is working */ | 141 /* should be done after syslog is working */ |
146 if (svr_opts.forkbg) { | 142 if (svr_opts.forkbg) { |
147 dropbear_log(LOG_INFO, "Running in background"); | 143 dropbear_log(LOG_INFO, "Running in background"); |
148 } else { | 144 } else { |
149 dropbear_log(LOG_INFO, "Not forking"); | 145 dropbear_log(LOG_INFO, "Not forking"); |
158 | 154 |
159 /* sockets to identify pre-authenticated clients */ | 155 /* sockets to identify pre-authenticated clients */ |
160 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 156 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
161 childpipes[i] = -1; | 157 childpipes[i] = -1; |
162 } | 158 } |
159 bzero(preauth_addrs, sizeof(preauth_addrs)); | |
163 | 160 |
164 /* Set up the listening sockets */ | 161 /* Set up the listening sockets */ |
165 /* XXX XXX ports */ | |
166 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); | 162 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); |
167 if (listensockcount < 0) { | 163 if (listensockcount == 0) |
164 { | |
168 dropbear_exit("No listening ports available."); | 165 dropbear_exit("No listening ports available."); |
169 } | 166 } |
170 | 167 |
171 /* incoming connection select loop */ | 168 /* incoming connection select loop */ |
172 for(;;) { | 169 for(;;) { |
175 | 172 |
176 seltimeout.tv_sec = 60; | 173 seltimeout.tv_sec = 60; |
177 seltimeout.tv_usec = 0; | 174 seltimeout.tv_usec = 0; |
178 | 175 |
179 /* listening sockets */ | 176 /* listening sockets */ |
180 for (i = 0; i < (unsigned int)listensockcount; i++) { | 177 for (i = 0; i < listensockcount; i++) { |
181 FD_SET(listensocks[i], &fds); | 178 FD_SET(listensocks[i], &fds); |
182 } | 179 } |
183 | 180 |
184 /* pre-authentication clients */ | 181 /* pre-authentication clients */ |
185 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 182 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
206 continue; | 203 continue; |
207 } | 204 } |
208 dropbear_exit("Listening socket error"); | 205 dropbear_exit("Listening socket error"); |
209 } | 206 } |
210 | 207 |
211 /* close fds which have been authed or closed - auth.c handles | 208 /* close fds which have been authed or closed - svr-auth.c handles |
212 * closing the auth sockets on success */ | 209 * closing the auth sockets on success */ |
213 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 210 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
214 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { | 211 if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { |
215 close(childpipes[i]); | 212 m_close(childpipes[i]); |
216 childpipes[i] = -1; | 213 childpipes[i] = -1; |
214 m_free(preauth_addrs[i]); | |
217 } | 215 } |
218 } | 216 } |
219 | 217 |
220 /* handle each socket which has something to say */ | 218 /* handle each socket which has something to say */ |
221 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 | |
222 if (!FD_ISSET(listensocks[i], &fds)) | 229 if (!FD_ISSET(listensocks[i], &fds)) |
223 continue; | 230 continue; |
224 | 231 |
225 remoteaddrlen = sizeof(remoteaddr); | 232 remoteaddrlen = sizeof(remoteaddr); |
226 childsock = accept(listensocks[i], | 233 childsock = accept(listensocks[i], |
229 if (childsock < 0) { | 236 if (childsock < 0) { |
230 /* accept failed */ | 237 /* accept failed */ |
231 continue; | 238 continue; |
232 } | 239 } |
233 | 240 |
234 /* 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; | |
235 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { | 246 for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { |
236 if (childpipes[j] < 0) { | 247 if (childpipes[j] >= 0) { |
237 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; | |
238 } | 255 } |
239 } | 256 } |
240 | 257 |
241 if (j == MAX_UNAUTH_CLIENTS) { | 258 if (num_unauthed_total >= MAX_UNAUTH_CLIENTS |
242 /* no free connections */ | 259 || num_unauthed_for_addr >= MAX_UNAUTH_PER_IP) { |
243 /* TODO - possibly log, though this would be an easy way | 260 goto out; |
244 * to fill logs/disk */ | |
245 close(childsock); | |
246 continue; | |
247 } | 261 } |
248 | 262 |
249 if (pipe(childpipe) < 0) { | 263 if (pipe(childpipe) < 0) { |
250 TRACE(("error creating child pipe")) | 264 TRACE(("error creating child pipe")) |
251 close(childsock); | 265 goto out; |
252 continue; | 266 } |
253 } | 267 |
254 | 268 fork_ret = fork(); |
255 if ((childpid = fork()) == 0) { | 269 if (fork_ret < 0) { |
270 dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno)); | |
271 goto out; | |
272 | |
273 } else if (fork_ret > 0) { | |
274 | |
275 /* parent */ | |
276 childpipes[conn_idx] = childpipe[0]; | |
277 m_close(childpipe[1]); | |
278 preauth_addrs[conn_idx] = remote_addr_str; | |
279 remote_addr_str = NULL; | |
280 | |
281 } else { | |
256 | 282 |
257 /* child */ | 283 /* child */ |
258 char * addrstring = NULL; | 284 char * addrstring = NULL; |
259 #ifdef DEBUG_FORKGPROF | 285 #ifdef DEBUG_FORKGPROF |
260 extern void _start(void), etext(void); | 286 extern void _start(void), etext(void); |
261 monstartup((u_long)&_start, (u_long)&etext); | 287 monstartup((u_long)&_start, (u_long)&etext); |
262 #endif /* DEBUG_FORKGPROF */ | 288 #endif /* DEBUG_FORKGPROF */ |
263 | 289 |
290 m_free(remote_addr_str); | |
264 addrstring = getaddrstring(&remoteaddr, 1); | 291 addrstring = getaddrstring(&remoteaddr, 1); |
265 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); | 292 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); |
266 | 293 |
267 if (setsid() < 0) { | 294 if (setsid() < 0) { |
268 dropbear_exit("setsid: %s", strerror(errno)); | 295 dropbear_exit("setsid: %s", strerror(errno)); |
269 } | 296 } |
270 | 297 |
271 /* make sure we close sockets */ | 298 /* make sure we close sockets */ |
272 for (i = 0; i < (unsigned int)listensockcount; i++) { | 299 for (i = 0; i < listensockcount; i++) { |
273 if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { | 300 m_close(listensocks[i]); |
274 dropbear_exit("Couldn't close socket"); | |
275 } | |
276 } | 301 } |
277 | 302 |
278 if (m_close(childpipe[0]) == DROPBEAR_FAILURE) { | 303 m_close(childpipe[0]); |
279 dropbear_exit("Couldn't close socket"); | |
280 } | |
281 | 304 |
282 /* start the session */ | 305 /* start the session */ |
283 svr_session(childsock, childpipe[1], | 306 svr_session(childsock, childpipe[1], |
284 getaddrhostname(&remoteaddr), | 307 getaddrhostname(&remoteaddr), |
285 addrstring); | 308 addrstring); |
286 /* don't return */ | 309 /* don't return */ |
287 dropbear_assert(0); | 310 dropbear_assert(0); |
288 } | 311 } |
289 | 312 |
290 /* parent */ | 313 out: |
291 childpipes[j] = childpipe[0]; | 314 /* This section is important for the parent too */ |
292 if (m_close(childpipe[1]) == DROPBEAR_FAILURE | 315 m_close(childsock); |
293 || m_close(childsock) == DROPBEAR_FAILURE) { | 316 if (remote_addr_str) { |
294 dropbear_exit("Couldn't close socket"); | 317 m_free(remote_addr_str); |
295 } | 318 } |
296 } | 319 } |
297 } /* for(;;) loop */ | 320 } /* for(;;) loop */ |
298 | 321 |
299 /* don't reach here */ | 322 /* don't reach here */ |
357 } | 380 } |
358 | 381 |
359 /* Now we can setup the hostkeys - needs to be after logging is on, | 382 /* 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 */ | 383 * otherwise we might end up blatting error messages to the socket */ |
361 loadhostkeys(); | 384 loadhostkeys(); |
385 | |
386 seedrandom(); | |
362 } | 387 } |
363 | 388 |
364 /* Set up listening sockets for all the requested ports */ | 389 /* Set up listening sockets for all the requested ports */ |
365 static int listensockets(int *sock, int sockcount, int *maxfd) { | 390 static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { |
366 | 391 |
367 unsigned int i; | 392 unsigned int i; |
368 char* errstring = NULL; | 393 char* errstring = NULL; |
369 unsigned int sockpos = 0; | 394 size_t sockpos = 0; |
370 int nsock; | 395 int nsock; |
371 | 396 |
372 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) | 397 TRACE(("listensockets: %d to try\n", svr_opts.portcount)) |
373 | 398 |
374 for (i = 0; i < svr_opts.portcount; i++) { | 399 for (i = 0; i < svr_opts.portcount; i++) { |