Ejemplo n.º 1
0
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();
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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);
}