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