Mercurial > dropbear
comparison svr-main.c @ 118:5312ca05ed48 private-rez
propagate of 717950f4061f1123659ee87c7c168805af920ab7 and 839f98f136788cc1466e4641bf796f96040a085d from branch 'matt.dbclient.authpam' to 'matt.dbclient.rez'
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 12 Sep 2004 04:56:50 +0000 |
parents | 775c6cbfe995 |
children | 8c2b3506f112 |
comparison
equal
deleted
inserted
replaced
57:3b2a5a1c4347 | 118:5312ca05ed48 |
---|---|
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 *maxfd); | 32 static int listensockets(int *sock, int 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 static void main_inetd(); | |
37 static void main_noinetd(); | |
38 static void commonsetup(); | |
36 | 39 |
37 static int childpipes[MAX_UNAUTH_CLIENTS]; | 40 static int childpipes[MAX_UNAUTH_CLIENTS]; |
38 | 41 |
39 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) | 42 #if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) |
40 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) | 43 #if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) |
42 #else | 45 #else |
43 int main(int argc, char ** argv) | 46 int main(int argc, char ** argv) |
44 #endif | 47 #endif |
45 { | 48 { |
46 | 49 |
50 | |
51 _dropbear_exit = svr_dropbear_exit; | |
52 _dropbear_log = svr_dropbear_log; | |
53 | |
54 /* get commandline options */ | |
55 svr_getopts(argc, argv); | |
56 | |
57 #ifdef INETD_MODE | |
58 /* service program mode */ | |
59 if (svr_opts.inetdmode) { | |
60 main_inetd(); | |
61 /* notreached */ | |
62 } | |
63 #endif | |
64 | |
65 #ifdef NON_INETD_MODE | |
66 main_noinetd(); | |
67 /* notreached */ | |
68 #endif | |
69 | |
70 dropbear_exit("Compiled without normal mode, can't run without -i\n"); | |
71 return -1; | |
72 } | |
73 #endif | |
74 | |
75 #ifdef INETD_MODE | |
76 static void main_inetd() { | |
77 | |
78 struct sockaddr_storage remoteaddr; | |
79 int remoteaddrlen; | |
80 char * addrstring = NULL; | |
81 | |
82 /* Set up handlers, syslog */ | |
83 commonsetup(); | |
84 | |
85 remoteaddrlen = sizeof(remoteaddr); | |
86 if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) { | |
87 dropbear_exit("Unable to getpeername: %s", strerror(errno)); | |
88 } | |
89 | |
90 /* In case our inetd was lax in logging source addresses */ | |
91 addrstring = getaddrstring(&remoteaddr, 1); | |
92 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); | |
93 m_free(addrstring); | |
94 | |
95 /* Don't check the return value - it may just fail since inetd has | |
96 * already done setsid() after forking (xinetd on Darwin appears to do | |
97 * this */ | |
98 setsid(); | |
99 | |
100 /* Start service program | |
101 * -1 is a dummy childpipe, just something we can close() without | |
102 * mattering. */ | |
103 svr_session(0, -1, getaddrhostname(&remoteaddr)); | |
104 | |
105 /* notreached */ | |
106 } | |
107 #endif /* INETD_MODE */ | |
108 | |
109 #ifdef NON_INETD_MODE | |
110 void main_noinetd() { | |
47 fd_set fds; | 111 fd_set fds; |
48 struct timeval seltimeout; | 112 struct timeval seltimeout; |
49 unsigned int i, j; | 113 unsigned int i, j; |
50 int val; | 114 int val; |
51 int maxsock = -1; | 115 int maxsock = -1; |
52 struct sockaddr remoteaddr; | 116 struct sockaddr_storage remoteaddr; |
53 int remoteaddrlen; | 117 int remoteaddrlen; |
54 int listensocks[MAX_LISTEN_ADDR]; | 118 int listensocks[MAX_LISTEN_ADDR]; |
55 unsigned int listensockcount = 0; | 119 int listensockcount = 0; |
56 FILE * pidfile; | 120 FILE *pidfile = NULL; |
57 | 121 |
58 int childsock; | 122 int childsock; |
59 pid_t childpid; | 123 pid_t childpid; |
60 int childpipe[2]; | 124 int childpipe[2]; |
61 | |
62 struct sigaction sa_chld; | |
63 | |
64 _dropbear_exit = svr_dropbear_exit; | |
65 _dropbear_log = svr_dropbear_log; | |
66 | |
67 /* get commandline options */ | |
68 svr_getopts(argc, argv); | |
69 | 125 |
70 /* fork */ | 126 /* fork */ |
71 if (svr_opts.forkbg) { | 127 if (svr_opts.forkbg) { |
72 int closefds = 0; | 128 int closefds = 0; |
73 #ifndef DEBUG_TRACE | 129 #ifndef DEBUG_TRACE |
74 if (!svr_opts.usingsyslog) { | 130 if (!svr_opts.usingsyslog) { |
75 closefds = 1; | 131 closefds = 1; |
76 } | 132 } |
77 #endif | 133 #endif |
78 if (daemon(0, closefds) < 0) { | 134 if (daemon(0, closefds) < 0) { |
79 dropbear_exit("Failed to create background process: %s", | 135 dropbear_exit("Failed to daemonize: %s", strerror(errno)); |
80 strerror(errno)); | 136 } |
81 } | 137 } |
82 } | 138 |
83 | 139 commonsetup(); |
84 #ifndef DISABLE_SYSLOG | 140 |
85 if (svr_opts.usingsyslog) { | |
86 startsyslog(); | |
87 } | |
88 #endif | |
89 | 141 |
90 /* should be done after syslog is working */ | 142 /* should be done after syslog is working */ |
91 if (svr_opts.forkbg) { | 143 if (svr_opts.forkbg) { |
92 dropbear_log(LOG_INFO, "Running in background"); | 144 dropbear_log(LOG_INFO, "Running in background"); |
93 } else { | 145 } else { |
99 if (pidfile) { | 151 if (pidfile) { |
100 fprintf(pidfile, "%d\n", getpid()); | 152 fprintf(pidfile, "%d\n", getpid()); |
101 fclose(pidfile); | 153 fclose(pidfile); |
102 } | 154 } |
103 | 155 |
104 /* set up cleanup handler */ | |
105 if (signal(SIGINT, sigintterm_handler) == SIG_ERR || | |
106 #ifndef DEBUG_VALGRIND | |
107 signal(SIGTERM, sigintterm_handler) == SIG_ERR || | |
108 #endif | |
109 signal(SIGPIPE, SIG_IGN) == SIG_ERR) { | |
110 dropbear_exit("signal() error"); | |
111 } | |
112 | |
113 /* catch and reap zombie children */ | |
114 sa_chld.sa_handler = sigchld_handler; | |
115 sa_chld.sa_flags = SA_NOCLDSTOP; | |
116 if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { | |
117 dropbear_exit("signal() error"); | |
118 } | |
119 if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { | |
120 dropbear_exit("signal() error"); | |
121 } | |
122 | |
123 /* sockets to identify pre-authenticated clients */ | 156 /* sockets to identify pre-authenticated clients */ |
124 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 157 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
125 childpipes[i] = -1; | 158 childpipes[i] = -1; |
126 } | 159 } |
127 | 160 |
128 /* Set up the listening sockets */ | 161 /* Set up the listening sockets */ |
129 /* XXX XXX ports */ | 162 /* XXX XXX ports */ |
130 listensockcount = listensockets(listensocks, &maxsock); | 163 listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); |
164 if (listensockcount < 0) { | |
165 dropbear_exit("No listening ports available."); | |
166 } | |
131 | 167 |
132 /* incoming connection select loop */ | 168 /* incoming connection select loop */ |
133 for(;;) { | 169 for(;;) { |
134 | 170 |
135 FD_ZERO(&fds); | 171 FD_ZERO(&fds); |
136 | 172 |
137 seltimeout.tv_sec = 60; | 173 seltimeout.tv_sec = 60; |
138 seltimeout.tv_usec = 0; | 174 seltimeout.tv_usec = 0; |
139 | 175 |
140 /* listening sockets */ | 176 /* listening sockets */ |
141 for (i = 0; i < listensockcount; i++) { | 177 for (i = 0; i < (unsigned int)listensockcount; i++) { |
142 FD_SET(listensocks[i], &fds); | 178 FD_SET(listensocks[i], &fds); |
143 } | 179 } |
144 | 180 |
145 /* pre-authentication clients */ | 181 /* pre-authentication clients */ |
146 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { | 182 for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { |
177 childpipes[i] = -1; | 213 childpipes[i] = -1; |
178 } | 214 } |
179 } | 215 } |
180 | 216 |
181 /* handle each socket which has something to say */ | 217 /* handle each socket which has something to say */ |
182 for (i = 0; i < listensockcount; i++) { | 218 for (i = 0; i < (unsigned int)listensockcount; i++) { |
183 if (!FD_ISSET(listensocks[i], &fds)) | 219 if (!FD_ISSET(listensocks[i], &fds)) |
184 continue; | 220 continue; |
185 | 221 |
186 /* child connection XXX - ip6 stuff here */ | 222 remoteaddrlen = sizeof(remoteaddr); |
187 remoteaddrlen = sizeof(struct sockaddr_in); | 223 childsock = accept(listensocks[i], |
188 childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen); | 224 (struct sockaddr*)&remoteaddr, &remoteaddrlen); |
189 | 225 |
190 if (childsock < 0) { | 226 if (childsock < 0) { |
191 /* accept failed */ | 227 /* accept failed */ |
192 continue; | 228 continue; |
193 } | 229 } |
220 #ifdef DEBUG_FORKGPROF | 256 #ifdef DEBUG_FORKGPROF |
221 extern void _start(void), etext(void); | 257 extern void _start(void), etext(void); |
222 monstartup((u_long)&_start, (u_long)&etext); | 258 monstartup((u_long)&_start, (u_long)&etext); |
223 #endif /* DEBUG_FORKGPROF */ | 259 #endif /* DEBUG_FORKGPROF */ |
224 | 260 |
225 addrstring = getaddrstring(&remoteaddr); | 261 addrstring = getaddrstring(&remoteaddr, 1); |
226 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); | 262 dropbear_log(LOG_INFO, "Child connection from %s", addrstring); |
227 m_free(addrstring); | 263 m_free(addrstring); |
228 | 264 |
229 if (setsid() < 0) { | 265 if (setsid() < 0) { |
230 dropbear_exit("setsid: %s", strerror(errno)); | 266 dropbear_exit("setsid: %s", strerror(errno)); |
231 } | 267 } |
232 | 268 |
233 /* make sure we close sockets */ | 269 /* make sure we close sockets */ |
234 for (i = 0; i < listensockcount; i++) { | 270 for (i = 0; i < (unsigned int)listensockcount; i++) { |
235 if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { | 271 if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { |
236 dropbear_exit("Couldn't close socket"); | 272 dropbear_exit("Couldn't close socket"); |
237 } | 273 } |
238 } | 274 } |
239 | 275 |
256 } | 292 } |
257 } | 293 } |
258 } /* for(;;) loop */ | 294 } /* for(;;) loop */ |
259 | 295 |
260 /* don't reach here */ | 296 /* don't reach here */ |
261 return -1; | 297 } |
262 } | 298 #endif /* NON_INETD_MODE */ |
263 #endif | 299 |
264 | 300 |
265 /* catch + reap zombie children */ | 301 /* catch + reap zombie children */ |
266 static void sigchld_handler(int fish) { | 302 static void sigchld_handler(int UNUSED(unused)) { |
267 struct sigaction sa_chld; | 303 struct sigaction sa_chld; |
268 | 304 |
269 while(waitpid(-1, NULL, WNOHANG) > 0); | 305 while(waitpid(-1, NULL, WNOHANG) > 0); |
270 | 306 |
271 sa_chld.sa_handler = sigchld_handler; | 307 sa_chld.sa_handler = sigchld_handler; |
274 dropbear_exit("signal() error"); | 310 dropbear_exit("signal() error"); |
275 } | 311 } |
276 } | 312 } |
277 | 313 |
278 /* catch any segvs */ | 314 /* catch any segvs */ |
279 static void sigsegv_handler(int fish) { | 315 static void sigsegv_handler(int UNUSED(unused)) { |
280 fprintf(stderr, "Aiee, segfault! You should probably report " | 316 fprintf(stderr, "Aiee, segfault! You should probably report " |
281 "this as a bug to the developer\n"); | 317 "this as a bug to the developer\n"); |
282 exit(EXIT_FAILURE); | 318 exit(EXIT_FAILURE); |
283 } | 319 } |
284 | 320 |
285 /* catch ctrl-c or sigterm */ | 321 /* catch ctrl-c or sigterm */ |
286 static void sigintterm_handler(int fish) { | 322 static void sigintterm_handler(int UNUSED(unused)) { |
287 | 323 |
288 exitflag = 1; | 324 exitflag = 1; |
289 } | 325 } |
290 | 326 |
327 /* Things used by inetd and non-inetd modes */ | |
328 static void commonsetup() { | |
329 | |
330 struct sigaction sa_chld; | |
331 #ifndef DISABLE_SYSLOG | |
332 if (svr_opts.usingsyslog) { | |
333 startsyslog(); | |
334 } | |
335 #endif | |
336 | |
337 /* set up cleanup handler */ | |
338 if (signal(SIGINT, sigintterm_handler) == SIG_ERR || | |
339 #ifndef DEBUG_VALGRIND | |
340 signal(SIGTERM, sigintterm_handler) == SIG_ERR || | |
341 #endif | |
342 signal(SIGPIPE, SIG_IGN) == SIG_ERR) { | |
343 dropbear_exit("signal() error"); | |
344 } | |
345 | |
346 /* catch and reap zombie children */ | |
347 sa_chld.sa_handler = sigchld_handler; | |
348 sa_chld.sa_flags = SA_NOCLDSTOP; | |
349 if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { | |
350 dropbear_exit("signal() error"); | |
351 } | |
352 if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { | |
353 dropbear_exit("signal() error"); | |
354 } | |
355 | |
356 /* Now we can setup the hostkeys - needs to be after logging is on, | |
357 * otherwise we might end up blatting error messages to the socket */ | |
358 loadhostkeys(); | |
359 } | |
360 | |
291 /* Set up listening sockets for all the requested ports */ | 361 /* Set up listening sockets for all the requested ports */ |
292 static int listensockets(int *sock, int *maxfd) { | 362 static int listensockets(int *sock, int sockcount, int *maxfd) { |
293 | 363 |
294 int listensock; /* listening fd */ | |
295 struct sockaddr_in listen_addr; | |
296 struct linger linger; | |
297 unsigned int i; | 364 unsigned int i; |
298 int val; | 365 char* errstring = NULL; |
366 unsigned int sockpos = 0; | |
367 int nsock; | |
368 | |
369 TRACE(("listensockets: %d to try\n", svr_opts.portcount)); | |
299 | 370 |
300 for (i = 0; i < svr_opts.portcount; i++) { | 371 for (i = 0; i < svr_opts.portcount; i++) { |
301 | 372 |
302 /* iterate through all the sockets to listen on */ | 373 TRACE(("listening on '%s'", svr_opts.ports[i])); |
303 listensock = socket(PF_INET, SOCK_STREAM, 0); | 374 |
304 if (listensock < 0) { | 375 nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos], |
305 dropbear_exit("Failed to create socket"); | 376 sockcount - sockpos, |
306 } | 377 &errstring, maxfd); |
307 | 378 |
308 val = 1; | 379 if (nsock < 0) { |
309 /* set to reuse, quick timeout */ | 380 dropbear_log(LOG_WARNING, "Failed listening on '%s': %s", |
310 setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, | 381 svr_opts.ports[i], errstring); |
311 (void*) &val, sizeof(val)); | 382 m_free(errstring); |
312 linger.l_onoff = 1; | 383 continue; |
313 linger.l_linger = 5; | 384 } |
314 setsockopt(listensock, SOL_SOCKET, SO_LINGER, | 385 |
315 (void*)&linger, sizeof(linger)); | 386 sockpos += nsock; |
316 | 387 |
317 /* disable nagle */ | 388 } |
318 setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY, | 389 return sockpos; |
319 (void*)&val, sizeof(val)); | 390 } |
320 | |
321 memset((void*)&listen_addr, 0x0, sizeof(listen_addr)); | |
322 listen_addr.sin_family = AF_INET; | |
323 listen_addr.sin_port = htons(svr_opts.ports[i]); | |
324 listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
325 memset(&(listen_addr.sin_zero), '\0', 8); | |
326 | |
327 if (bind(listensock, (struct sockaddr *)&listen_addr, | |
328 sizeof(listen_addr)) < 0) { | |
329 dropbear_exit("Bind failed port %d", svr_opts.ports[i]); | |
330 } | |
331 | |
332 /* listen */ | |
333 if (listen(listensock, 20) < 0) { /* TODO set listen count */ | |
334 dropbear_exit("Listen failed"); | |
335 } | |
336 | |
337 /* nonblock */ | |
338 if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) { | |
339 dropbear_exit("Failed to set non-blocking"); | |
340 } | |
341 | |
342 sock[i] = listensock; | |
343 *maxfd = MAX(listensock, *maxfd); | |
344 } | |
345 | |
346 return svr_opts.portcount; | |
347 } |