static void httpProcessInput() { struct sockaddr_in addr; int addrlen = sizeof(addr); char fullFname[512]; char params[1024]; char *ptr; char *fname; int maxFnameLen; int fd; Bool performSubstitutions = FALSE; char str[256]; struct passwd *user; user = getpwuid(getuid()); if (strlen(httpDir) > 255) { rfbLog("-httpd directory too long\n"); httpCloseSock(); return; } strcpy(fullFname, httpDir); fname = &fullFname[strlen(fullFname)]; maxFnameLen = 511 - strlen(fullFname); /* Read data from the HTTP client until we get a complete request. */ while (1) { ssize_t got = read (httpSock, buf + buf_filled, sizeof (buf) - buf_filled - 1); if (got <= 0) { if (got == 0) { rfbLog("httpd: premature connection close\n"); } else { if (errno == EAGAIN) { return; } rfbLogPerror("httpProcessInput: read"); } httpCloseSock(); return; } buf_filled += got; buf[buf_filled] = '\0'; /* Is it complete yet (is there a blank line)? */ if (strstr (buf, "\r\r") || strstr (buf, "\n\n") || strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r")) break; } /* Process the request. */ if (strncmp(buf, "GET ", 4)) { rfbLog("httpd: no GET line\n"); httpCloseSock(); return; } else { /* Only use the first line. */ buf[strcspn(buf, "\n\r")] = '\0'; } if (strlen(buf) > maxFnameLen) { rfbLog("httpd: GET line too long\n"); httpCloseSock(); return; } if (sscanf(buf, "GET %s HTTP/1.0", fname) != 1) { rfbLog("httpd: couldn't parse GET line\n"); httpCloseSock(); return; } if (fname[0] != '/') { rfbLog("httpd: filename didn't begin with '/'\n"); WriteExact(httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(); return; } if (strchr(fname+1, '/') != NULL) { rfbLog("httpd: asking for file in other directory\n"); WriteExact(httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(); return; } getpeername(httpSock, (struct sockaddr *)&addr, &addrlen); rfbLog("httpd: get '%s' for %s\n", fname+1, inet_ntoa(addr.sin_addr)); /* Extract parameters from the URL string if necessary */ params[0] = '\0'; ptr = strchr(fname, '?'); if (ptr != NULL) { *ptr = '\0'; if (!parseParams(&ptr[1], params, 1024)) { params[0] = '\0'; rfbLog("httpd: bad parameters in the URL\n"); } } /* If we were asked for '/', actually read the file index.vnc */ if (strcmp(fname, "/") == 0) { strcpy(fname, "/index.vnc"); rfbLog("httpd: defaulting to '%s'\n", fname+1); } /* Substitutions are performed on files ending .vnc */ if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) { performSubstitutions = TRUE; } /* Open the file */ if ((fd = open(fullFname, O_RDONLY)) < 0) { rfbLogPerror("httpProcessInput: open"); WriteExact(httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(); return; } WriteExact(httpSock, OK_STR, strlen(OK_STR)); while (1) { int n = read(fd, buf, BUF_SIZE-1); if (n < 0) { rfbLogPerror("httpProcessInput: read"); close(fd); httpCloseSock(); return; } if (n == 0) break; if (performSubstitutions) { /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values. This won't quite work properly if the .vnc file is longer than BUF_SIZE, but it's reasonable to assume that .vnc files will always be short. */ char *ptr = buf; char *dollar; buf[n] = 0; /* make sure it's null-terminated */ while (dollar = strchr(ptr, '$')) { WriteExact(httpSock, ptr, (dollar - ptr)); ptr = dollar; if (compareAndSkip(&ptr, "$WIDTH")) { sprintf(str, "%d", rfbScreen.width); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$HEIGHT")) { sprintf(str, "%d", rfbScreen.height); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) { sprintf(str, "%d", rfbScreen.width); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) { sprintf(str, "%d", rfbScreen.height + 32); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$PORT")) { sprintf(str, "%d", rfbPort); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$DESKTOP")) { WriteExact(httpSock, desktopName, strlen(desktopName)); } else if (compareAndSkip(&ptr, "$DISPLAY")) { sprintf(str, "%s:%s", rfbThisHost, display); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$USER")) { if (user) { WriteExact(httpSock, user->pw_name, strlen(user->pw_name)); } else { WriteExact(httpSock, "?", 1); } } else if (compareAndSkip(&ptr, "$PARAMS")) { if (params[0] != '\0') WriteExact(httpSock, params, strlen(params)); } else { if (!compareAndSkip(&ptr, "$$")) ptr++; if (WriteExact(httpSock, "$", 1) < 0) { close(fd); httpCloseSock(); return; } } } if (WriteExact(httpSock, ptr, (&buf[n] - ptr)) < 0) break; } else { /* For files not ending .vnc, just write out the buffer */ if (WriteExact(httpSock, buf, n) < 0) break; } } close(fd); httpCloseSock(); }
static void httpProcessInput(rfbScreenInfoPtr rfbScreen) { #ifdef LIBVNCSERVER_IPv6 struct sockaddr_storage addr; char host[1024]; #else struct sockaddr_in addr; #endif socklen_t addrlen = sizeof(addr); char fullFname[512]; char params[1024]; char *ptr; char *fname; unsigned int maxFnameLen; FILE* fd; rfbBool performSubstitutions = FALSE; char str[256+32]; #ifndef WIN32 char* user=getenv("USER"); #endif cl.sock=rfbScreen->httpSock; if (strlen(rfbScreen->httpDir) > 255) { rfbErr("-httpd directory too long\n"); httpCloseSock(rfbScreen); return; } strcpy(fullFname, rfbScreen->httpDir); fname = &fullFname[strlen(fullFname)]; maxFnameLen = 511 - strlen(fullFname); buf_filled=0; /* Read data from the HTTP client until we get a complete request. */ while (1) { ssize_t got; if (buf_filled > sizeof (buf)) { rfbErr("httpProcessInput: HTTP request is too long\n"); httpCloseSock(rfbScreen); return; } got = read (rfbScreen->httpSock, buf + buf_filled, sizeof (buf) - buf_filled - 1); if (got <= 0) { if (got == 0) { rfbErr("httpd: premature connection close\n"); } else { #ifdef WIN32 errno=WSAGetLastError(); #endif if (errno == EAGAIN) { return; } rfbLogPerror("httpProcessInput: read"); } httpCloseSock(rfbScreen); return; } buf_filled += got; buf[buf_filled] = '\0'; /* Is it complete yet (is there a blank line)? */ if (strstr (buf, "\r\r") || strstr (buf, "\n\n") || strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r")) break; } /* Process the request. */ if(rfbScreen->httpEnableProxyConnect) { const static char* PROXY_OK_STR = "HTTP/1.0 200 OK\r\nContent-Type: octet-stream\r\nPragma: no-cache\r\n\r\n"; if(!strncmp(buf, "CONNECT ", 8)) { if(atoi(strchr(buf, ':')+1)!=rfbScreen->port) { rfbErr("httpd: CONNECT format invalid.\n"); rfbWriteExact(&cl,INVALID_REQUEST_STR, strlen(INVALID_REQUEST_STR)); httpCloseSock(rfbScreen); return; } /* proxy connection */ rfbLog("httpd: client asked for CONNECT\n"); rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR)); rfbNewClientConnection(rfbScreen,rfbScreen->httpSock); rfbScreen->httpSock = -1; return; } if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) { /* proxy connection */ rfbLog("httpd: client asked for /proxied.connection\n"); rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR)); rfbNewClientConnection(rfbScreen,rfbScreen->httpSock); rfbScreen->httpSock = -1; return; } } if (strncmp(buf, "GET ", 4)) { rfbErr("httpd: no GET line\n"); httpCloseSock(rfbScreen); return; } else { /* Only use the first line. */ buf[strcspn(buf, "\n\r")] = '\0'; } if (strlen(buf) > maxFnameLen) { rfbErr("httpd: GET line too long\n"); httpCloseSock(rfbScreen); return; } if (sscanf(buf, "GET %s HTTP/1.", fname) != 1) { rfbErr("httpd: couldn't parse GET line\n"); httpCloseSock(rfbScreen); return; } if (fname[0] != '/') { rfbErr("httpd: filename didn't begin with '/'\n"); rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen); #ifdef LIBVNCSERVER_IPv6 if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { rfbLogPerror("httpProcessInput: error in getnameinfo"); } rfbLog("httpd: get '%s' for %s\n", fname+1, host); #else rfbLog("httpd: get '%s' for %s\n", fname+1, inet_ntoa(addr.sin_addr)); #endif /* Extract parameters from the URL string if necessary */ params[0] = '\0'; ptr = strchr(fname, '?'); if (ptr != NULL) { *ptr = '\0'; if (!parseParams(&ptr[1], params, 1024)) { params[0] = '\0'; rfbErr("httpd: bad parameters in the URL\n"); } } /* If we were asked for '/', actually read the file index.vnc */ if (strcmp(fname, "/") == 0) { strcpy(fname, "/index.vnc"); rfbLog("httpd: defaulting to '%s'\n", fname+1); } /* Substitutions are performed on files ending .vnc */ if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) { performSubstitutions = TRUE; } /* Open the file */ if ((fd = fopen(fullFname, "r")) == 0) { rfbLogPerror("httpProcessInput: open"); rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } if(performSubstitutions) /* is the 'index.vnc' file */ rfbWriteExact(&cl, OK_STR_HTML, strlen(OK_STR_HTML)); else rfbWriteExact(&cl, OK_STR, strlen(OK_STR)); while (1) { int n = fread(buf, 1, BUF_SIZE-1, fd); if (n < 0) { rfbLogPerror("httpProcessInput: read"); fclose(fd); httpCloseSock(rfbScreen); return; } if (n == 0) break; if (performSubstitutions) { /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values. This won't quite work properly if the .vnc file is longer than BUF_SIZE, but it's reasonable to assume that .vnc files will always be short. */ char *ptr = buf; char *dollar; buf[n] = 0; /* make sure it's null-terminated */ while ((dollar = strchr(ptr, '$'))!=NULL) { rfbWriteExact(&cl, ptr, (dollar - ptr)); ptr = dollar; if (compareAndSkip(&ptr, "$WIDTH")) { sprintf(str, "%d", rfbScreen->width); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$HEIGHT")) { sprintf(str, "%d", rfbScreen->height); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) { sprintf(str, "%d", rfbScreen->width); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) { sprintf(str, "%d", rfbScreen->height + 32); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$PORT")) { sprintf(str, "%d", rfbScreen->port); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$DESKTOP")) { rfbWriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName)); } else if (compareAndSkip(&ptr, "$DISPLAY")) { sprintf(str, "%s:%d", rfbScreen->thisHost, rfbScreen->port-5900); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$USER")) { #ifndef WIN32 if (user) { rfbWriteExact(&cl, user, strlen(user)); } else #endif rfbWriteExact(&cl, "?", 1); } else if (compareAndSkip(&ptr, "$PARAMS")) { if (params[0] != '\0') rfbWriteExact(&cl, params, strlen(params)); } else { if (!compareAndSkip(&ptr, "$$")) ptr++; if (rfbWriteExact(&cl, "$", 1) < 0) { fclose(fd); httpCloseSock(rfbScreen); return; } } } if (rfbWriteExact(&cl, ptr, (&buf[n] - ptr)) < 0) break; } else { /* For files not ending .vnc, just write out the buffer */ if (rfbWriteExact(&cl, buf, n) < 0) break; } } fclose(fd); httpCloseSock(rfbScreen); }
static void httpProcessInput(rfbScreenInfoPtr rfbScreen) { struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); char fullFname[256]; char *fname; unsigned int maxFnameLen; FILE* fd; Bool performSubstitutions = FALSE; char str[256]; #ifndef WIN32 struct passwd *user = getpwuid(getuid()); #endif cl.sock=rfbScreen->httpSock; if (strlen(rfbScreen->httpDir) > 200) { rfbLog("-httpd directory too long\n"); httpCloseSock(rfbScreen); return; } strcpy(fullFname, rfbScreen->httpDir); fname = &fullFname[strlen(fullFname)]; maxFnameLen = 255 - strlen(fullFname); /* Read data from the HTTP client until we get a complete request. */ while (1) { ssize_t got = read (rfbScreen->httpSock, buf + buf_filled, sizeof (buf) - buf_filled - 1); if (got <= 0) { if (got == 0) { rfbLog("httpd: premature connection close\n"); } else { if (errno == EAGAIN) { return; } rfbLogPerror("httpProcessInput: read"); } httpCloseSock(rfbScreen); return; } buf_filled += got; buf[buf_filled] = '\0'; /* Is it complete yet (is there a blank line)? */ if (strstr (buf, "\r\r") || strstr (buf, "\n\n") || strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r")) break; } /* Process the request. */ if (strncmp(buf, "GET ", 4)) { rfbLog("no GET line\n"); httpCloseSock(rfbScreen); return; } else { /* Only use the first line. */ buf[strcspn(buf, "\n\r")] = '\0'; } if (strlen(buf) > maxFnameLen) { rfbLog("GET line too long\n"); httpCloseSock(rfbScreen); return; } if (sscanf(buf, "GET %s HTTP/1.0", fname) != 1) { rfbLog("couldn't parse GET line\n"); httpCloseSock(rfbScreen); return; } if (fname[0] != '/') { rfbLog("filename didn't begin with '/'\n"); WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } if (strchr(fname+1, '/') != NULL) { rfbLog("asking for file in other directory\n"); WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen); rfbLog("httpd: get '%s' for %s\n", fname+1, inet_ntoa(addr.sin_addr)); /* If we were asked for '/', actually read the file index.vnc */ if (strcmp(fname, "/") == 0) { strcpy(fname, "/index.vnc"); rfbLog("httpd: defaulting to '%s'\n", fname+1); } /* Substitutions are performed on files ending .vnc */ if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) { performSubstitutions = TRUE; } /* Open the file */ if ((fd = fopen(fullFname, "r")) <= 0) { rfbLogPerror("httpProcessInput: open"); WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } WriteExact(&cl, OK_STR, strlen(OK_STR)); while (1) { int n = fread(buf, 1, BUF_SIZE-1, fd); if (n < 0) { rfbLogPerror("httpProcessInput: read"); fclose(fd); httpCloseSock(rfbScreen); return; } if (n == 0) break; if (performSubstitutions) { /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values. This won't quite work properly if the .vnc file is longer than BUF_SIZE, but it's reasonable to assume that .vnc files will always be short. */ char *ptr = buf; char *dollar; buf[n] = 0; /* make sure it's null-terminated */ while ((dollar = strchr(ptr, '$'))!=NULL) { WriteExact(&cl, ptr, (dollar - ptr)); ptr = dollar; if (compareAndSkip(&ptr, "$WIDTH")) { sprintf(str, "%d", rfbScreen->width); WriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$HEIGHT")) { sprintf(str, "%d", rfbScreen->height); WriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) { sprintf(str, "%d", rfbScreen->width); WriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) { sprintf(str, "%d", rfbScreen->height + 32); WriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$PORT")) { sprintf(str, "%d", rfbScreen->rfbPort); WriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$DESKTOP")) { WriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName)); } else if (compareAndSkip(&ptr, "$DISPLAY")) { sprintf(str, "%s:%d", rfbScreen->rfbThisHost, rfbScreen->rfbPort-5900); WriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$USER")) { #ifndef WIN32 if (user) { WriteExact(&cl, user->pw_name, strlen(user->pw_name)); } else #endif WriteExact(&cl, "?", 1); } else { if (!compareAndSkip(&ptr, "$$")) ptr++; if (WriteExact(&cl, "$", 1) < 0) { fclose(fd); httpCloseSock(rfbScreen); return; } } } if (WriteExact(&cl, ptr, (&buf[n] - ptr)) < 0) break; } else { /* For files not ending .vnc, just write out the buffer */ if (WriteExact(&cl, buf, n) < 0) break; } } fclose(fd); httpCloseSock(rfbScreen); }