--- sshd.c.orig Mon Mar 10 01:38:10 2003 +++ sshd.c Wed May 14 02:47:07 2003 @@ -52,6 +52,11 @@ #include #include #endif +#ifdef DOUBLE_AS_HTTPD +#include +#include +#include +#endif #include "ssh.h" #include "ssh1.h" @@ -483,6 +488,152 @@ } } +#ifdef DOUBLE_AS_HTTPD +static void sshd_act_like_an_httpd(int sock_in, int sock_out); +static void sshd_httpd_timeout(int sig); + +/* intercept httpd */ +static void +sshd_intercept_possible_httpd(int sock_in, int sock_out) +{ + struct sockaddr local; + int local_len; + fd_set readfds; + struct timeval onesec; + + local_len = sizeof(local); + if ( getsockname(sock_in, &local, &local_len) != 0 ) { + log("HTTPD HACK: getsockname failed: %.100s", + strerror(errno)); + return; + } + if ( local.sa_family != AF_INET ) { + log("HTTPD HACK: strange sock_in.sa_family: %d", + local.sa_family); + return; + } + if ( ntohs(((struct sockaddr_in*) &local)->sin_port) != 80 ) { + /* XXX this logging should be removed */ + log("HTTPD HACK: incoming port not 80 but %d", + ntohs(((struct sockaddr_in*) &local)->sin_port)); + return; + } + + /* wait 1 second for a valid http request coming in */ + FD_ZERO(&readfds); + FD_SET(sock_in, &readfds); + onesec.tv_sec = 1; + onesec.tv_usec = 0; + if ( ! select(sock_in + 1, &readfds, NULL, NULL, &onesec) ) { + log("HTTPD HACK: nothing incoming for 1 second"); + return; + } + if ( ! FD_ISSET(sock_in, &readfds) ) { + log("HTTPD HACK: hm, sock_in not readable"); + return; + } + + /* + * Something is in the buffer right now. This is not an ssh client. + * so from here on, we will never return to the real program, + * and assume it is an HTTP request. + */ + + sshd_act_like_an_httpd(sock_in, sock_out); + exit(0); +} + +static void +sshd_act_like_an_httpd(int sock_in, int sock_out) +{ + FILE* in; + char httpreq[1024]; + char hdrline[1024]; + char outbuf[4096]; + char* p; + char* url; + + /* setup an alarm call to abort playing HTTPD reasonably soon. */ + signal(SIGALRM, sshd_httpd_timeout); + if (!debug_flag) + alarm(60); + + if ( !(in = fdopen(sock_in, "r+")) ) { + log("HTTPD HACK: fdopen failed: %.100s", strerror(errno)); + return; + } + + /* read in the first line of the request */ + if ( ! fgets(httpreq, sizeof(httpreq), in) ) { + log("HTTPD HACK: fgets failed on first line: %.100s", + strerror(errno)); + return; + } + + /* must be a GET request... for NOW. Support more */ + if ( strncmp(httpreq, "GET ", 4) ) { + log("HTTPD HACK: no GET request, but a %.100s", httpreq); + return; + } + url = httpreq + 4; + + if ( !(p = strchr(url, ' ')) ) { + log("HTTPD HACK: HTTP/0.9 request: %.100s", httpreq); + return; + } + + *p++ = '\0'; + /* must be a HTTP/1.x request */ + if ( strncmp(p, "HTTP/1.", 7) ) { + log("HTTPD HACK: Not a HTTP/1.x request but %.100s", p); + return; + } + + log("HTTPD HACK: faking a request for GET %.100s", url); + + /* read (and ignore) the subsequent header */ + strcpy(hdrline, "foo"); + while ( strlen(hdrline) > 0 ) { + if ( ! fgets(hdrline, sizeof(hdrline), in) ) { + log("HTTPD HACK: fgets failed on header: %.100s", + strerror(errno)); + return; + } + /* strip CR+LF */ + if ( (p = strchr(hdrline, '\r')) != NULL ) + *p = '\0'; + if ( (p = strchr(hdrline, '\n')) != NULL ) + *p = '\0'; + log("HTTPD HACK: ignoring header %.100s", hdrline); + } + + /* output the redirect. To a fixed site for proof of concept. */ + snprintf(outbuf, sizeof(outbuf), "\ +HTTP/1.0 301 Don't be so lazy and type that www\r\n\ +Server: sshd %.100s\r\n\ +Location: http://www.xs4all.nl%s\r\n\ +Connection: close\r\n\ +Content-Type: text/plain\r\n\ +\r\n\ +Don't be so lazy, and simply type www.xs4all.nl instead of just xs4all.nl\r\n\ +", + SSH_VERSION, + url + ); + write(sock_out, &outbuf, strlen(outbuf)); + return; +} + +static void +sshd_httpd_timeout(int sig) +{ + /* Log error and exit. */ + fatal("Timeout in acting like HTTPD for connection from %s", + get_remote_ipaddr()); +} + +#endif + /* Destroy the host and server keys. They will no longer be needed. */ void destroy_sensitive_data(void) @@ -1457,6 +1608,14 @@ /* Log the connection. */ verbose("Connection from %.500s port %d", remote_ip, remote_port); + +#ifdef DOUBLE_AS_HTTPD + /* + * Wait a few instants to see if an HTTP request comes in, + * then handle that. This is only done for port 80. + */ + sshd_intercept_possible_httpd(sock_in, sock_out); +#endif /* * We don\'t want to listen forever unless the other side