Mercurial > dropbear
diff 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 |
line wrap: on
line diff
--- a/svr-main.c Sun Aug 08 16:57:37 2004 +0000 +++ b/svr-main.c Sun Sep 12 04:56:50 2004 +0000 @@ -29,10 +29,13 @@ #include "signkey.h" #include "runopts.h" -static int listensockets(int *sock, int *maxfd); +static int listensockets(int *sock, int sockcount, int *maxfd); static void sigchld_handler(int dummy); static void sigsegv_handler(int); static void sigintterm_handler(int fish); +static void main_inetd(); +static void main_noinetd(); +static void commonsetup(); static int childpipes[MAX_UNAUTH_CLIENTS]; @@ -44,22 +47,6 @@ #endif { - fd_set fds; - struct timeval seltimeout; - unsigned int i, j; - int val; - int maxsock = -1; - struct sockaddr remoteaddr; - int remoteaddrlen; - int listensocks[MAX_LISTEN_ADDR]; - unsigned int listensockcount = 0; - FILE * pidfile; - - int childsock; - pid_t childpid; - int childpipe[2]; - - struct sigaction sa_chld; _dropbear_exit = svr_dropbear_exit; _dropbear_log = svr_dropbear_log; @@ -67,6 +54,75 @@ /* get commandline options */ svr_getopts(argc, argv); +#ifdef INETD_MODE + /* service program mode */ + if (svr_opts.inetdmode) { + main_inetd(); + /* notreached */ + } +#endif + +#ifdef NON_INETD_MODE + main_noinetd(); + /* notreached */ +#endif + + dropbear_exit("Compiled without normal mode, can't run without -i\n"); + return -1; +} +#endif + +#ifdef INETD_MODE +static void main_inetd() { + + struct sockaddr_storage remoteaddr; + int remoteaddrlen; + char * addrstring = NULL; + + /* Set up handlers, syslog */ + commonsetup(); + + remoteaddrlen = sizeof(remoteaddr); + if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) { + dropbear_exit("Unable to getpeername: %s", strerror(errno)); + } + + /* In case our inetd was lax in logging source addresses */ + addrstring = getaddrstring(&remoteaddr, 1); + dropbear_log(LOG_INFO, "Child connection from %s", addrstring); + m_free(addrstring); + + /* Don't check the return value - it may just fail since inetd has + * already done setsid() after forking (xinetd on Darwin appears to do + * this */ + setsid(); + + /* Start service program + * -1 is a dummy childpipe, just something we can close() without + * mattering. */ + svr_session(0, -1, getaddrhostname(&remoteaddr)); + + /* notreached */ +} +#endif /* INETD_MODE */ + +#ifdef NON_INETD_MODE +void main_noinetd() { + fd_set fds; + struct timeval seltimeout; + unsigned int i, j; + int val; + int maxsock = -1; + struct sockaddr_storage remoteaddr; + int remoteaddrlen; + int listensocks[MAX_LISTEN_ADDR]; + int listensockcount = 0; + FILE *pidfile = NULL; + + int childsock; + pid_t childpid; + int childpipe[2]; + /* fork */ if (svr_opts.forkbg) { int closefds = 0; @@ -76,16 +132,12 @@ } #endif if (daemon(0, closefds) < 0) { - dropbear_exit("Failed to create background process: %s", - strerror(errno)); + dropbear_exit("Failed to daemonize: %s", strerror(errno)); } } -#ifndef DISABLE_SYSLOG - if (svr_opts.usingsyslog) { - startsyslog(); - } -#endif + commonsetup(); + /* should be done after syslog is working */ if (svr_opts.forkbg) { @@ -101,25 +153,6 @@ fclose(pidfile); } - /* set up cleanup handler */ - if (signal(SIGINT, sigintterm_handler) == SIG_ERR || -#ifndef DEBUG_VALGRIND - signal(SIGTERM, sigintterm_handler) == SIG_ERR || -#endif - signal(SIGPIPE, SIG_IGN) == SIG_ERR) { - dropbear_exit("signal() error"); - } - - /* catch and reap zombie children */ - sa_chld.sa_handler = sigchld_handler; - sa_chld.sa_flags = SA_NOCLDSTOP; - if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { - dropbear_exit("signal() error"); - } - if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { - dropbear_exit("signal() error"); - } - /* sockets to identify pre-authenticated clients */ for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { childpipes[i] = -1; @@ -127,7 +160,10 @@ /* Set up the listening sockets */ /* XXX XXX ports */ - listensockcount = listensockets(listensocks, &maxsock); + listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); + if (listensockcount < 0) { + dropbear_exit("No listening ports available."); + } /* incoming connection select loop */ for(;;) { @@ -138,7 +174,7 @@ seltimeout.tv_usec = 0; /* listening sockets */ - for (i = 0; i < listensockcount; i++) { + for (i = 0; i < (unsigned int)listensockcount; i++) { FD_SET(listensocks[i], &fds); } @@ -179,13 +215,13 @@ } /* handle each socket which has something to say */ - for (i = 0; i < listensockcount; i++) { + for (i = 0; i < (unsigned int)listensockcount; i++) { if (!FD_ISSET(listensocks[i], &fds)) continue; - /* child connection XXX - ip6 stuff here */ - remoteaddrlen = sizeof(struct sockaddr_in); - childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen); + remoteaddrlen = sizeof(remoteaddr); + childsock = accept(listensocks[i], + (struct sockaddr*)&remoteaddr, &remoteaddrlen); if (childsock < 0) { /* accept failed */ @@ -222,7 +258,7 @@ monstartup((u_long)&_start, (u_long)&etext); #endif /* DEBUG_FORKGPROF */ - addrstring = getaddrstring(&remoteaddr); + addrstring = getaddrstring(&remoteaddr, 1); dropbear_log(LOG_INFO, "Child connection from %s", addrstring); m_free(addrstring); @@ -231,7 +267,7 @@ } /* make sure we close sockets */ - for (i = 0; i < listensockcount; i++) { + for (i = 0; i < (unsigned int)listensockcount; i++) { if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { dropbear_exit("Couldn't close socket"); } @@ -258,12 +294,12 @@ } /* for(;;) loop */ /* don't reach here */ - return -1; } -#endif +#endif /* NON_INETD_MODE */ + /* catch + reap zombie children */ -static void sigchld_handler(int fish) { +static void sigchld_handler(int UNUSED(unused)) { struct sigaction sa_chld; while(waitpid(-1, NULL, WNOHANG) > 0); @@ -276,72 +312,79 @@ } /* catch any segvs */ -static void sigsegv_handler(int fish) { +static void sigsegv_handler(int UNUSED(unused)) { fprintf(stderr, "Aiee, segfault! You should probably report " "this as a bug to the developer\n"); exit(EXIT_FAILURE); } /* catch ctrl-c or sigterm */ -static void sigintterm_handler(int fish) { +static void sigintterm_handler(int UNUSED(unused)) { exitflag = 1; } +/* Things used by inetd and non-inetd modes */ +static void commonsetup() { + + struct sigaction sa_chld; +#ifndef DISABLE_SYSLOG + if (svr_opts.usingsyslog) { + startsyslog(); + } +#endif + + /* set up cleanup handler */ + if (signal(SIGINT, sigintterm_handler) == SIG_ERR || +#ifndef DEBUG_VALGRIND + signal(SIGTERM, sigintterm_handler) == SIG_ERR || +#endif + signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + dropbear_exit("signal() error"); + } + + /* catch and reap zombie children */ + sa_chld.sa_handler = sigchld_handler; + sa_chld.sa_flags = SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { + dropbear_exit("signal() error"); + } + if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { + dropbear_exit("signal() error"); + } + + /* Now we can setup the hostkeys - needs to be after logging is on, + * otherwise we might end up blatting error messages to the socket */ + loadhostkeys(); +} + /* Set up listening sockets for all the requested ports */ -static int listensockets(int *sock, int *maxfd) { +static int listensockets(int *sock, int sockcount, int *maxfd) { - int listensock; /* listening fd */ - struct sockaddr_in listen_addr; - struct linger linger; unsigned int i; - int val; + char* errstring = NULL; + unsigned int sockpos = 0; + int nsock; + + TRACE(("listensockets: %d to try\n", svr_opts.portcount)); for (i = 0; i < svr_opts.portcount; i++) { - /* iterate through all the sockets to listen on */ - listensock = socket(PF_INET, SOCK_STREAM, 0); - if (listensock < 0) { - dropbear_exit("Failed to create socket"); + TRACE(("listening on '%s'", svr_opts.ports[i])); + + nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos], + sockcount - sockpos, + &errstring, maxfd); + + if (nsock < 0) { + dropbear_log(LOG_WARNING, "Failed listening on '%s': %s", + svr_opts.ports[i], errstring); + m_free(errstring); + continue; } - val = 1; - /* set to reuse, quick timeout */ - setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, - (void*) &val, sizeof(val)); - linger.l_onoff = 1; - linger.l_linger = 5; - setsockopt(listensock, SOL_SOCKET, SO_LINGER, - (void*)&linger, sizeof(linger)); - - /* disable nagle */ - setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY, - (void*)&val, sizeof(val)); - - memset((void*)&listen_addr, 0x0, sizeof(listen_addr)); - listen_addr.sin_family = AF_INET; - listen_addr.sin_port = htons(svr_opts.ports[i]); - listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); - memset(&(listen_addr.sin_zero), '\0', 8); + sockpos += nsock; - if (bind(listensock, (struct sockaddr *)&listen_addr, - sizeof(listen_addr)) < 0) { - dropbear_exit("Bind failed port %d", svr_opts.ports[i]); - } - - /* listen */ - if (listen(listensock, 20) < 0) { /* TODO set listen count */ - dropbear_exit("Listen failed"); - } - - /* nonblock */ - if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) { - dropbear_exit("Failed to set non-blocking"); - } - - sock[i] = listensock; - *maxfd = MAX(listensock, *maxfd); } - - return svr_opts.portcount; + return sockpos; }