void SendFileDownloadLengthErrMsg(rfbClientPtr cl) { FileTransferMsg fileDownloadErrMsg; memset(&fileDownloadErrMsg, 0 , sizeof(FileTransferMsg)); fileDownloadErrMsg = GetFileDownloadLengthErrResponseMsg(); if((fileDownloadErrMsg.data == NULL) || (fileDownloadErrMsg.length == 0)) { rfbLog("File [%s]: Method [%s]: Unexpected error: fileDownloadErrMsg " "is null\n", __FILE__, __FUNCTION__); return; } rfbWriteExact(cl, fileDownloadErrMsg.data, fileDownloadErrMsg.length); FreeFileTransferMsg(fileDownloadErrMsg); }
void rfbAuthRevokeUser(const char* name) { UserList** prev = &userACL; UserList* p; rfbLog("Removing user '%s' from ACL\n", name); while (*prev != NULL) { p = *prev; if (!strcmp(p->name, name)) { *prev = p->next; xfree(p->name); xfree(p); return; } prev = &p->next; } }
static void idle(rfbScreenInfo* server) { int c; rfbBool goForward; LOCK(statisticsMutex); #ifdef ALL_AT_ONCE goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST); #else goForward=(countGotUpdate==1); #endif /* if(lastUpdateRect.x2==354) rfbLog("server checked: countGotUpdate=%d\n",countGotUpdate); */ UNLOCK(statisticsMutex); if(!goForward) return; countGotUpdate=0; LOCK(frameBufferMutex); { int i,j; int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)), y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1)); if(x1>x2) { i=x1; x1=x2; x2=i; } if(y1>y2) { i=y1; y1=y2; y2=i; } x2++; y2++; for(c=0;c<3;c++) { for(i=x1;i<x2;i++) for(j=y1;j<y2;j++) server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1); } rfbMarkRectAsModified(server,x1,y1,x2,y2); lastUpdateRect.x1=x1; lastUpdateRect.y1=y1; lastUpdateRect.x2=x2; lastUpdateRect.y2=y2; #ifdef VERY_VERBOSE rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2); #endif } UNLOCK(frameBufferMutex); }
/* * getBgColour() gets the most prevalent colour in a byte array. */ static uint32_t getBgColour(char *data, int size, int bpp) { #define NUMCLRS 256 static int counts[NUMCLRS]; int i,j,k; int maxcount = 0; uint8_t maxclr = 0; if (bpp != 8) { if (bpp == 16) { return ((uint16_t *)data)[0]; } else if (bpp == 32) { return ((uint32_t *)data)[0]; } else { rfbLog("getBgColour: bpp %d?\n",bpp); return 0; } } for (i=0; i<NUMCLRS; i++) { counts[i] = 0; } for (j=0; j<size; j++) { k = (int)(((uint8_t *)data)[j]); if (k >= NUMCLRS) { rfbErr("getBgColour: unusual colour = %d\n", k); return 0; } counts[k] += 1; if (counts[k] > maxcount) { maxcount = counts[k]; maxclr = ((uint8_t *)data)[j]; } } return maxclr; }
void FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp) { /* Here we are settimg the modification and access time of the file */ /* Windows code stes mod/access/creation time of the file */ struct utimbuf utb; utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime; if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) { rfbLog("File [%s]: Method [%s]: Setting the modification/access" " time for the file <%s> failed\n", __FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName); } if(rtcp->rcft.rcfu.uploadFD != -1) { close(rtcp->rcft.rcfu.uploadFD); rtcp->rcft.rcfu.uploadFD = -1; rtcp->rcft.rcfu.uploadInProgress = FALSE; } }
/* * This is called whenever a client fence message is received. */ void HandleFence(rfbClientPtr cl, CARD32 flags, unsigned len, const char *data) { RTTInfo rttInfo; if (flags & rfbFenceFlagRequest) { if (flags & rfbFenceFlagSyncNext) { cl->pendingSyncFence = TRUE; cl->fenceFlags = flags & (rfbFenceFlagBlockBefore | rfbFenceFlagBlockAfter | rfbFenceFlagSyncNext); cl->fenceDataLen = len; if (len > 0) memcpy(cl->fenceData, data, len); return; } /* We handle everything synchronously, so we trivially honor these modes */ flags = flags & (rfbFenceFlagBlockBefore | rfbFenceFlagBlockAfter); rfbSendFence(cl, flags, len, data); return; } switch (len) { case 0: // Initial dummy fence break; case sizeof(RTTInfo): memcpy(&rttInfo, data, sizeof(RTTInfo)); HandleRTTPong(cl, &rttInfo); break; default: rfbLog("Fence of unusual size received\n"); } }
void avahi_reset(void) { int i; if (db) fprintf(stderr, "in avahi_reset\n"); for (i=0; i<NREG; i++) { if (registered[i].name) { free(registered[i].name); registered[i].name = NULL; } if (registered[i].host) { free(registered[i].host); registered[i].host = NULL; } } if (!_client || !_group) { if (db) fprintf(stderr, " avahi_reset client/group null\n"); return; } avahi_entry_group_reset(_group); rfbLog("Avahi resetting group.\n"); if (db) fprintf(stderr, "out avahi_reset\n"); }
static rfbBool handleMessage(rfbClientPtr cl, const char* messageName, void (*handler)(rfbClientPtr cl, rfbTightClientPtr data)) { rfbTightClientPtr data; rfbLog("tightvnc-filetransfer: %s message received\n", messageName); if((IsFileTransferEnabled() == FALSE) || ( cl->viewOnly == TRUE)) { rfbCloseClient(cl); return FALSE; } data = rfbGetTightClientData(cl); if(data == NULL) return FALSE; handler(cl, data); return TRUE; }
/* * When the console sends the File Transfer Request, it sends the file path with * ftproot as "/". So on Agent, to get the absolute file path we need to prepend * the ftproot to it. */ char* ConvertPath(char* path) { char p[PATH_MAX]; memset(p, 0, PATH_MAX); if( (path == NULL) || (strlen(path) == 0) || (strlen(path)+strlen(ftproot) > PATH_MAX - 1) ) { rfbLog("File [%s]: Method [%s]: cannot create path for file transfer\n", __FILE__, __FUNCTION__); return NULL; } memcpy(p, path, strlen(path)); memset(path, 0, PATH_MAX); sprintf(path, "%s%s", ftproot, p); return path; }
rfbBool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w, int h) { rfbFramebufferUpdateRectHeader rect; if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingHextile); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; rfbStatRecordEncodingSent(cl, rfbEncodingHextile, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h); switch (cl->format.bitsPerPixel) { case 8: return sendHextiles8(cl, x, y, w, h); case 16: return sendHextiles16(cl, x, y, w, h); case 32: return sendHextiles32(cl, x, y, w, h); } rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel); return FALSE; }
void clean_shm(int quick) { int i, cnt = 0; /* * to avoid deadlock, etc, under quick=1 we just delete the shm * areas and leave the X stuff hanging. */ if (quick) { shm_delete(&scanline_shm); shm_delete(&fullscreen_shm); shm_delete(&snaprect_shm); } else { shm_clean(&scanline_shm, scanline); shm_clean(&fullscreen_shm, fullscreen); shm_clean(&snaprect_shm, snaprect); } /* * Here we have to clean up quite a few shm areas for all * the possible tile row runs (40 for 1280), not as robust * as one might like... sometimes need to run ipcrm(1). */ for(i=1; i<=ntiles_x; i++) { if (i > tile_shm_count) { break; } if (quick) { shm_delete(&tile_row_shm[i]); } else { shm_clean(&tile_row_shm[i], tile_row[i]); } cnt++; if (single_copytile_count && i >= single_copytile_count) { break; } } if (!quiet && cnt > 0) { rfbLog("deleted %d tile_row polling images.\n", cnt); } }
static void rfbSendTunnelingCaps(rfbClientPtr cl) { rfbTunnelingCapsMsg caps; uint32_t nTypes = 0; /* we don't support tunneling yet */ rfbLog("tightvnc-filetransfer/rfbSendTunnelingCaps\n"); caps.nTunnelTypes = Swap32IfLE(nTypes); if (rfbWriteExact(cl, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) { rfbLogPerror("rfbSendTunnelingCaps: write"); rfbCloseClient(cl); return; } if (nTypes) { /* Dispatch client input to rfbProcessClientTunnelingType(). */ /* The flow should not reach here as tunneling is not implemented. */ rfbProcessClientTunnelingType(cl); } else { rfbSendAuthCaps(cl); } }
void InitFileTransfer() { char* userHome = NULL; uid_t uid = geteuid(); if(fileTransferInitted) return; rfbLog("tightvnc-filetransfer/InitFileTransfer\n"); memset(ftproot, 0, sizeof(ftproot)); userHome = GetHomeDir(uid); if((userHome != NULL) && (strlen(userHome) != 0)) { SetFtpRoot(userHome); FreeHomeDir(userHome); } fileTransferEnabled = TRUE; fileTransferInitted = TRUE; }
int rfbConnect(rfbScreenInfoPtr rfbScreen, char *host, int port) { int sock; int one = 1; rfbLog("Making connection to client on host %s port %d\n", host,port); if ((sock = rfbConnectToTcpAddr(host, port)) < 0) { rfbLogPerror("connection failed"); return -1; } #ifndef WIN32 if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { rfbLogPerror("fcntl failed"); closesocket(sock); return -1; } #endif if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { rfbLogPerror("setsockopt failed"); closesocket(sock); return -1; } /* AddEnabledDevice(sock); */ FD_SET(sock, &rfbScreen->allFds); rfbScreen->maxFd = max(sock,rfbScreen->maxFd); return sock; }
static void rfbVncAuthNone(rfbClientPtr cl) { /* The built-in Mac OS X VNC client behaves in a non-conforming fashion * when the server version is 3.7 or later AND the list of security types * sent to the OS X client contains the 'None' authentication type AND * the OS X client sends back the 'None' type as its choice. In this case, * and this case ONLY, the built-in Mac OS X VNC client will NOT send the * ClientInit message and instead will behave as though an implicit * ClientInit message containing a shared-flag of true has been sent. * The special state RFB_INITIALISATION_SHARED represents this case. * The Mac OS X VNC client can be detected by checking protocolMinorVersion * for a value of 889. No other VNC client is known to use this value * for protocolMinorVersion. */ uint32_t authResult; /* The built-in Mac OS X VNC client expects to NOT receive a SecurityResult * message for authentication type 'None'. Since its protocolMinorVersion * is greater than 7 (it is 889) this case must be tested for specially. */ if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7 && cl->protocolMinorVersion != 889) { rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n"); authResult = Swap32IfLE(rfbVncAuthOK); if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { rfbLogPerror("rfbAuthProcessClientMessage: write"); rfbCloseClient(cl); return; } } cl->state = cl->protocolMinorVersion == 889 ? RFB_INITIALISATION_SHARED : RFB_INITIALISATION; if (cl->state == RFB_INITIALISATION_SHARED) /* In this case we must call rfbProcessClientMessage now because * otherwise we would hang waiting for data to be received from the * client (the ClientInit message which will never come). */ rfbProcessClientMessage(cl); return; }
void CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp) { /* TODO :: File Upload case is not handled currently */ /* TODO :: In case of concurrency we need to use Critical Section */ if(cl == NULL) return; if(rtcp->rcft.rcfu.uploadInProgress == TRUE) { rtcp->rcft.rcfu.uploadInProgress = FALSE; if(rtcp->rcft.rcfu.uploadFD != -1) { close(rtcp->rcft.rcfu.uploadFD); rtcp->rcft.rcfu.uploadFD = -1; } if(unlink(rtcp->rcft.rcfu.fName) == -1) { rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n", __FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName); } memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX); } if(rtcp->rcft.rcfd.downloadInProgress == TRUE) { rtcp->rcft.rcfd.downloadInProgress = FALSE; if(rtcp->rcft.rcfd.downloadFD != -1) { close(rtcp->rcft.rcfd.downloadFD); rtcp->rcft.rcfd.downloadFD = -1; } memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX); } }
void rfbPrintStats(rfbClientPtr cl) { int i; int totalRectanglesSent = 0; int totalBytesSent = 0; rfbLog("Statistics:"); if ((cl->rfbKeyEventsRcvd != 0) || (cl->rfbPointerEventsRcvd != 0)) rfbLog(" key events received %d, pointer events %d", cl->rfbKeyEventsRcvd, cl->rfbPointerEventsRcvd); for (i = 0; i < MAX_ENCODINGS; i++) { totalRectanglesSent += cl->rfbRectanglesSent[i]; totalBytesSent += cl->rfbBytesSent[i]; } totalRectanglesSent += cl->rfbLastRectMarkersSent; totalBytesSent += cl->rfbLastRectBytesSent; rfbLog(" framebuffer updates %d, rectangles %d, bytes %d", cl->rfbFramebufferUpdateMessagesSent, totalRectanglesSent, totalBytesSent); if (cl->rfbLastRectMarkersSent != 0) rfbLog(" LastRect markers %d, bytes %d", cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent); for (i = 0; i < MAX_ENCODINGS; i++) { if (cl->rfbRectanglesSent[i] != 0) rfbLog(" %s rectangles %d, bytes %d", encNames[i], cl->rfbRectanglesSent[i], cl->rfbBytesSent[i]); } if ((totalBytesSent - cl->rfbBytesSent[rfbEncodingCopyRect]) != 0) { rfbLog(" raw bytes equivalent %d, compression ratio %f", cl->rfbRawBytesEquivalent, (double)cl->rfbRawBytesEquivalent / (double)(totalBytesSent - cl->rfbBytesSent[rfbEncodingCopyRect] - cl->rfbLastRectBytesSent)); } }
void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen) { int nfds; fd_set fds; struct timeval tv; #ifdef LIBVNCSERVER_IPv6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen = sizeof(addr); if (!rfbScreen->httpDir) return; if (rfbScreen->httpListenSock < 0) return; FD_ZERO(&fds); FD_SET(rfbScreen->httpListenSock, &fds); if (rfbScreen->httpListen6Sock >= 0) { FD_SET(rfbScreen->httpListen6Sock, &fds); } if (rfbScreen->httpSock >= 0) { FD_SET(rfbScreen->httpSock, &fds); } tv.tv_sec = 0; tv.tv_usec = 0; nfds = select(max(rfbScreen->httpListen6Sock, max(rfbScreen->httpSock,rfbScreen->httpListenSock)) + 1, &fds, NULL, NULL, &tv); if (nfds == 0) { return; } if (nfds < 0) { #ifdef WIN32 errno = WSAGetLastError(); #endif if (errno != EINTR) rfbLogPerror("httpCheckFds: select"); return; } if ((rfbScreen->httpSock >= 0) && FD_ISSET(rfbScreen->httpSock, &fds)) { httpProcessInput(rfbScreen); } if (FD_ISSET(rfbScreen->httpListenSock, &fds) || FD_ISSET(rfbScreen->httpListen6Sock, &fds)) { if (rfbScreen->httpSock >= 0) close(rfbScreen->httpSock); if(FD_ISSET(rfbScreen->httpListenSock, &fds)) { if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, (struct sockaddr *)&addr, &addrlen)) < 0) { rfbLogPerror("httpCheckFds: accept"); return; } } else if(FD_ISSET(rfbScreen->httpListen6Sock, &fds)) { if ((rfbScreen->httpSock = accept(rfbScreen->httpListen6Sock, (struct sockaddr *)&addr, &addrlen)) < 0) { rfbLogPerror("httpCheckFds: accept"); return; } } #ifdef USE_LIBWRAP char host[1024]; #ifdef LIBVNCSERVER_IPv6 if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { rfbLogPerror("httpCheckFds: error in getnameinfo"); host[0] = '\0'; } #else memcpy(host, inet_ntoa(addr.sin_addr), sizeof(host)); #endif if(!hosts_ctl("vnc",STRING_UNKNOWN, host, STRING_UNKNOWN)) { rfbLog("Rejected HTTP connection from client %s\n", host); close(rfbScreen->httpSock); rfbScreen->httpSock=-1; return; } #endif if(!rfbSetNonBlocking(rfbScreen->httpSock)) { close(rfbScreen->httpSock); rfbScreen->httpSock=-1; return; } /*AddEnabledDevice(httpSock);*/ } }
void HandleFileUploadRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) { int n = 0; char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */ rfbClientToServerTightMsg msg; memset(path, 0, PATH_MAX); memset(&msg, 0, sizeof(rfbClientToServerTightMsg)); if(cl == NULL) { rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadRequestMsg-1)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } msg.fupr.fNameSize = Swap16IfLE(msg.fupr.fNameSize); msg.fupr.position = Swap16IfLE(msg.fupr.position); if ((msg.fupr.fNameSize == 0) || (msg.fupr.fNameSize > (PATH_MAX - 1))) { rfbLog("File [%s]: Method [%s]: error: path length is greater than PATH_MAX\n", __FILE__, __FUNCTION__); HandleFileUploadLengthError(cl, msg.fupr.fNameSize); return; } if((n = rfbReadExact(cl, rtcp->rcft.rcfu.fName, msg.fupr.fNameSize)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n" __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } rtcp->rcft.rcfu.fName[msg.fupr.fNameSize] = '\0'; if(ConvertPath(rtcp->rcft.rcfu.fName) == NULL) { rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL\n", __FILE__, __FUNCTION__); /* This may come if the path length exceeds PATH_MAX. So sending path length error to client */ SendFileUploadLengthErrMsg(cl); return; } HandleFileUpload(cl, rtcp); }
/* * HandleFileListRequest method is called when the server receives * FileListRequest. In case of success a file list is sent to the client. * For File List Request there is no failure reason sent.So here in case of any * "unexpected" error no information will be sent. As these conditions should * never come. Lets hope it never arrives :) * In case of dir open failure an empty list will be sent, just the header of * the message filled up. So on console you will get an Empty listing. */ void HandleFileListRequest(rfbClientPtr cl, rfbTightClientRec* data) { rfbClientToServerTightMsg msg; int n = 0; char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */ FileTransferMsg fileListMsg; memset(&msg, 0, sizeof(rfbClientToServerTightMsg)); memset(path, 0, PATH_MAX); memset(&fileListMsg, 0, sizeof(FileTransferMsg)); if(cl == NULL) { rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileListRequestMsg-1)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Socket error while reading dir name" " length\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } msg.flr.dirNameSize = Swap16IfLE(msg.flr.dirNameSize); if ((msg.flr.dirNameSize == 0) || (msg.flr.dirNameSize > (PATH_MAX - 1))) { rfbLog("File [%s]: Method [%s]: Unexpected error:: path length is " "greater that PATH_MAX\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, path, msg.flr.dirNameSize)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Socket error while reading dir name\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } if(ConvertPath(path) == NULL) { /* The execution should never reach here */ rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL", __FILE__, __FUNCTION__); return; } fileListMsg = GetFileListResponseMsg(path, (char) (msg.flr.flags)); if((fileListMsg.data == NULL) || (fileListMsg.length == 0)) { rfbLog("File [%s]: Method [%s]: Unexpected error:: Data to be sent is " "of Zero length\n", __FILE__, __FUNCTION__); return; } rfbWriteExact(cl, fileListMsg.data, fileListMsg.length); FreeFileTransferMsg(fileListMsg); }
static void check_fbpm(void) { static int init_fbpm = 0; #if LIBVNCSERVER_HAVE_FBPM static int fbpm_capable = 0; static time_t last_fbpm = 0; int db = 0; CARD16 level; BOOL enabled; RAWFB_RET_VOID if (! init_fbpm) { if (getenv("FBPM_DEBUG")) { db = atoi(getenv("FBPM_DEBUG")); } if (FBPMCapable(dpy)) { fbpm_capable = 1; rfbLog("X display is capable of FBPM.\n"); if (watch_fbpm) { rfbLog("Preventing low-power FBPM modes when" " clients are connected.\n"); } } else { if (! raw_fb_str) { rfbLog("X display is not capable of FBPM.\n"); } fbpm_capable = 0; } init_fbpm = 1; } if (! watch_fbpm) { return; } if (! fbpm_capable) { return; } if (! client_count) { return; } if (time(NULL) < last_fbpm + 5) { return; } last_fbpm = time(NULL); if (FBPMInfo(dpy, &level, &enabled)) { if (db) fprintf(stderr, "FBPMInfo level: %d enabled: %d\n", level, enabled); if (enabled && level != FBPMModeOn) { char *from = "unknown-fbpm-state"; XErrorHandler old_handler = XSetErrorHandler(trap_xerror); trapped_xerror = 0; if (level == FBPMModeStandby) { from = "FBPMModeStandby"; } else if (level == FBPMModeSuspend) { from = "FBPMModeSuspend"; } else if (level == FBPMModeOff) { from = "FBPMModeOff"; } rfbLog("switching FBPM state from %s to FBPMModeOn\n", from); FBPMForceLevel(dpy, FBPMModeOn); XSetErrorHandler(old_handler); trapped_xerror = 0; } } else { if (db) fprintf(stderr, "FBPMInfo failed.\n"); } #else RAWFB_RET_VOID if (! init_fbpm) { if (! raw_fb_str) { rfbLog("X FBPM extension not supported.\n"); } init_fbpm = 1; } #endif }
static void check_dpms(void) { static int init_dpms = 0; #if LIBVNCSERVER_HAVE_DPMS static int dpms_capable = 0; static time_t last_dpms = 0; int db = 0; CARD16 level; BOOL enabled; RAWFB_RET_VOID if (! init_dpms) { if (getenv("DPMS_DEBUG")) { db = atoi(getenv("DPMS_DEBUG")); } if (DPMSCapable(dpy)) { dpms_capable = 1; rfbLog("X display is capable of DPMS.\n"); if (watch_dpms) { rfbLog("Preventing low-power DPMS modes when" " clients are connected.\n"); } } else { if (! raw_fb_str) { rfbLog("X display is not capable of DPMS.\n"); } dpms_capable = 0; } init_dpms = 1; } if (force_dpms || (client_dpms && client_count)) { static int last_enable = 0; if (time(NULL) > last_enable) { set_dpms_mode("enable"); last_enable = time(NULL); } set_dpms_mode("off"); } if (! watch_dpms) { return; } if (! dpms_capable) { return; } if (! client_count) { return; } if (time(NULL) < last_dpms + 5) { return; } last_dpms = time(NULL); if (DPMSInfo(dpy, &level, &enabled)) { if (db) fprintf(stderr, "DPMSInfo level: %d enabled: %d\n", level, enabled); if (enabled && level != DPMSModeOn) { char *from = "unknown-dpms-state"; XErrorHandler old_handler = XSetErrorHandler(trap_xerror); trapped_xerror = 0; if (level == DPMSModeStandby) { from = "DPMSModeStandby"; } else if (level == DPMSModeSuspend) { from = "DPMSModeSuspend"; } else if (level == DPMSModeOff) { from = "DPMSModeOff"; } rfbLog("switching DPMS state from %s to DPMSModeOn\n", from); DPMSForceLevel(dpy, DPMSModeOn); XSetErrorHandler(old_handler); trapped_xerror = 0; } } else { if (db) fprintf(stderr, "DPMSInfo failed.\n"); } #else RAWFB_RET_VOID if (! init_dpms) { if (! raw_fb_str) { rfbLog("X DPMS extension not supported.\n"); } init_dpms = 1; } #endif }
int connect_tcp(char *host, int port) { double t0 = dnow(); int fd = -1; int fail4 = noipv4; if (getenv("IPV4_FAILS")) { fail4 = 2; } rfbLog("connect_tcp: trying: %s %d\n", host, port); if (fail4) { if (fail4 > 1) { rfbLog("TESTING: IPV4_FAILS for connect_tcp.\n"); } } else { fd = rfbConnectToTcpAddr(host, port); } if (fd >= 0) { return fd; } rfbLogPerror("connect_tcp: connection failed"); if (dnow() - t0 < 4.0) { rfbLog("connect_tcp: re-trying %s %d\n", host, port); usleep (100 * 1000); if (!fail4) { fd = rfbConnectToTcpAddr(host, port); } if (fd < 0) { rfbLogPerror("connect_tcp: connection failed"); } } if (fd < 0 && !noipv6) { #if X11VNC_IPV6 int err; struct addrinfo *ai; struct addrinfo hints; char service[32], *host2, *q; rfbLog("connect_tcp: trying IPv6 %s %d\n", host, port); memset(&hints, 0, sizeof(hints)); sprintf(service, "%d", port); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif if(ipv6_ip(host)) { #ifdef AI_NUMERICHOST rfbLog("connect_tcp[ipv6]: setting AI_NUMERICHOST for %s\n", host); hints.ai_flags |= AI_NUMERICHOST; #endif } #ifdef AI_NUMERICSERV hints.ai_flags |= AI_NUMERICSERV; #endif if (!strcmp(host, "127.0.0.1")) { host2 = strdup("::1"); } else if (host[0] == '[') { host2 = strdup(host+1); } else { host2 = strdup(host); } q = strrchr(host2, ']'); if (q) { *q = '\0'; } err = getaddrinfo(host2, service, &hints, &ai); if (err != 0) { rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err)); usleep(100 * 1000); err = getaddrinfo(host2, service, &hints, &ai); } free(host2); if (err != 0) { rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err)); } else { struct addrinfo *ap = ai; while (ap != NULL) { int sock; if (fail4) { struct sockaddr_in6 *s6ptr; if (ap->ai_family != AF_INET6) { rfbLog("connect_tcp[ipv6]: skipping AF_INET address under -noipv4\n"); ap = ap->ai_next; continue; } #ifdef IN6_IS_ADDR_V4MAPPED s6ptr = (struct sockaddr_in6 *) ap->ai_addr; if (IN6_IS_ADDR_V4MAPPED(&(s6ptr->sin6_addr))) { rfbLog("connect_tcp[ipv6]: skipping V4MAPPED address under -noipv4\n"); ap = ap->ai_next; continue; } #endif } sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); if (sock == -1) { rfbLogPerror("connect_tcp[ipv6]: socket"); if (0) rfbLog("(Ignore the above error if this system is IPv4-only.)\n"); } else { int res = -1, dmsg = 0; char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen); if (!s) s = strdup("unknown"); rfbLog("connect_tcp[ipv6]: trying sock=%d fam=%d proto=%d using %s\n", sock, ap->ai_family, ap->ai_protocol, s); res = connect(sock, ap->ai_addr, ap->ai_addrlen); #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) if (res != 0) { int zero = 0; rfbLogPerror("connect_tcp[ipv6]: connect"); dmsg = 1; if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) { rfbLog("connect_tcp[ipv6]: trying again with IPV6_V6ONLY=0\n"); res = connect(sock, ap->ai_addr, ap->ai_addrlen); dmsg = 0; } else { rfbLogPerror("connect_tcp[ipv6]: setsockopt IPV6_V6ONLY"); } } #endif if (res == 0) { rfbLog("connect_tcp[ipv6]: connect OK\n"); fd = sock; if (!ipv6_client_ip_str) { ipv6_client_ip_str = strdup(s); } free(s); break; } else { if (!dmsg) rfbLogPerror("connect_tcp[ipv6]: connect"); close(sock); } free(s); } ap = ap->ai_next; } freeaddrinfo(ai); } #endif } if (fd < 0 && !fail4) { /* this is a kludge for IPv4-only machines getting v4mapped string. */ char *q, *host2; if (host[0] == '[') { host2 = strdup(host+1); } else { host2 = strdup(host); } q = strrchr(host2, ']'); if (q) { *q = '\0'; } if (strstr(host2, "::ffff:") == host2 || strstr(host2, "::FFFF:") == host2) { char *host3 = host2 + strlen("::ffff:"); if (dotted_ip(host3, 0)) { rfbLog("connect_tcp[ipv4]: trying fallback to IPv4 for %s\n", host2); fd = rfbConnectToTcpAddr(host3, port); if (fd < 0) { rfbLogPerror("connect_tcp[ipv4]: connection failed"); } } } free(host2); } return fd; }
int listen6(int port) { #if X11VNC_IPV6 struct sockaddr_in6 sin; int fd = -1, one = 1; if (noipv6) { return -1; } if (port <= 0 || 65535 < port) { /* for us, invalid port means do not listen. */ return -1; } fd = socket(AF_INET6, SOCK_STREAM, 0); if (fd < 0) { rfbLogPerror("listen6: socket"); rfbLog("(Ignore the above error if this system is IPv4-only.)\n"); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) { rfbLogPerror("listen6: setsockopt SO_REUSEADDR"); close(fd); return -1; } #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) { rfbLogPerror("listen6: setsockopt IPV6_V6ONLY"); close(fd); return -1; } #endif memset((char *)&sin, 0, sizeof(sin)); sin.sin6_family = AF_INET6; sin.sin6_port = htons(port); sin.sin6_addr = in6addr_any; if (listen_str6) { if (!strcmp(listen_str6, "localhost") || !strcmp(listen_str6, "::1")) { sin.sin6_addr = in6addr_loopback; } else { int err; struct addrinfo *ai; struct addrinfo hints; char service[32]; memset(&hints, 0, sizeof(hints)); sprintf(service, "%d", port); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif #ifdef AI_NUMERICHOST if(ipv6_ip(listen_str6)) { hints.ai_flags |= AI_NUMERICHOST; } #endif #ifdef AI_NUMERICSERV hints.ai_flags |= AI_NUMERICSERV; #endif err = getaddrinfo(listen_str6, service, &hints, &ai); if (err == 0) { struct addrinfo *ap = ai; err = 1; while (ap != NULL) { char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen); if (!s) s = strdup("unknown"); rfbLog("listen6: checking: %s family: %d\n", s, ap->ai_family); if (ap->ai_family == AF_INET6) { memcpy((char *)&sin, ap->ai_addr, sizeof(sin)); rfbLog("listen6: using: %s scope_id: %d\n", s, sin.sin6_scope_id); err = 0; free(s); break; } free(s); ap = ap->ai_next; } freeaddrinfo(ai); } if (err != 0) { rfbLog("Invalid or Unsupported -listen6 string: %s\n", listen_str6); close(fd); return -1; } } } else if (allow_list && !strcmp(allow_list, "127.0.0.1")) { sin.sin6_addr = in6addr_loopback; } else if (listen_str) { if (!strcmp(listen_str, "localhost")) { sin.sin6_addr = in6addr_loopback; } } if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { rfbLogPerror("listen6: bind"); close(fd); return -1; } if (listen(fd, 32) < 0) { rfbLogPerror("listen6: listen"); close(fd); return -1; } return fd; #else if (port) {} return -1; #endif }
char *ident_username(rfbClientPtr client) { ClientData *cd = (ClientData *) client->clientData; char *str, *newhost, *user = NULL, *newuser = NULL; int len; if (cd) { user = cd->username; } if (!user || *user == '\0') { int n, sock, ok = 0; int block = 0; int refused = 0; /* * need to check to see if the operation will block for * a long time: a firewall may just ignore our packets. */ #if LIBVNCSERVER_HAVE_FORK { pid_t pid, pidw; int rc; if ((pid = fork()) > 0) { usleep(100 * 1000); /* 0.1 sec for quick success or refusal */ pidw = waitpid(pid, &rc, WNOHANG); if (pidw <= 0) { usleep(1500 * 1000); /* 1.5 sec */ pidw = waitpid(pid, &rc, WNOHANG); if (pidw <= 0) { int rc2; rfbLog("ident_username: set block=1 (hung)\n"); block = 1; kill(pid, SIGTERM); usleep(100 * 1000); waitpid(pid, &rc2, WNOHANG); } } if (pidw > 0 && !block) { if (WIFEXITED(rc) && WEXITSTATUS(rc) == 1) { rfbLog("ident_username: set refused=1 (exit)\n"); refused = 1; } } } else if (pid == -1) { ; } else { /* child */ signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); if ((sock = connect_tcp(client->host, 113)) < 0) { exit(1); } else { close(sock); exit(0); } } } #endif if (block || refused) { ; } else if ((sock = connect_tcp(client->host, 113)) < 0) { rfbLog("ident_username: could not connect to ident: %s:%d\n", client->host, 113); } else { char msg[128]; int ret; fd_set rfds; struct timeval tv; int rport = get_remote_port(client->sock); int lport = get_local_port(client->sock); sprintf(msg, "%d, %d\r\n", rport, lport); n = write(sock, msg, strlen(msg)); FD_ZERO(&rfds); FD_SET(sock, &rfds); tv.tv_sec = 3; tv.tv_usec = 0; ret = select(sock+1, &rfds, NULL, NULL, &tv); if (ret > 0) { int i; char *q, *p; for (i=0; i < (int) sizeof(msg); i++) { msg[i] = '\0'; } usleep(250*1000); n = read(sock, msg, 127); close(sock); if (n <= 0) goto badreply; /* 32782 , 6000 : USERID : UNIX :runge */ q = strstr(msg, "USERID"); if (!q) goto badreply; q = strstr(q, ":"); if (!q) goto badreply; q++; q = strstr(q, ":"); if (!q) goto badreply; q++; q = lblanks(q); p = q; while (*p) { if (*p == '\r' || *p == '\n') { *p = '\0'; } p++; } ok = 1; if (strlen(q) > 24) { *(q+24) = '\0'; } newuser = strdup(q); badreply: n = 0; /* avoid syntax error */ } else { close(sock); } } if (! ok || !newuser) { newuser = strdup("unknown-user"); } if (cd) { if (cd->username) { free(cd->username); } cd->username = newuser; } user = newuser; } if (!strcmp(user, "unknown-user") && cd && cd->unixname[0] != '\0') { user = cd->unixname; } if (unixpw && openssl_last_ip && strstr("UNIX:", user) != user) { newhost = ip2host(openssl_last_ip); } else { newhost = ip2host(client->host); } len = strlen(user) + 1 + strlen(newhost) + 1; str = (char *) malloc(len); sprintf(str, "%s@%s", user, newhost); free(newhost); return str; }
int check_xrandr_event(char *msg) { XEvent xev; RAWFB_RET(0) /* it is assumed that X_LOCK is on at this point. */ if (subwin) { return handle_subwin_resize(msg); } #if LIBVNCSERVER_HAVE_LIBXRANDR if (! xrandr_present) { return 0; } if (! xrandr && ! xrandr_maybe) { return 0; } if (xrandr_base_event_type && XCheckTypedEvent(dpy, xrandr_base_event_type + RRScreenChangeNotify, &xev)) { int do_change, qout = 0; static int first = 1; XRRScreenChangeNotifyEvent *rev; rev = (XRRScreenChangeNotifyEvent *) &xev; if (first && ! xrandr) { fprintf(stderr, "\n"); if (getenv("X11VNC_DEBUG_XRANDR") == NULL) { qout = 1; } } first = 0; rfbLog("check_xrandr_event():\n"); rfbLog("Detected XRANDR event at location '%s':\n", msg); if (qout) { ; } else { rfbLog(" serial: %d\n", (int) rev->serial); rfbLog(" timestamp: %d\n", (int) rev->timestamp); rfbLog(" cfg_timestamp: %d\n", (int) rev->config_timestamp); rfbLog(" size_id: %d\n", (int) rev->size_index); rfbLog(" sub_pixel: %d\n", (int) rev->subpixel_order); rfbLog(" rotation: %d\n", (int) rev->rotation); rfbLog(" width: %d\n", (int) rev->width); rfbLog(" height: %d\n", (int) rev->height); rfbLog(" mwidth: %d mm\n", (int) rev->mwidth); rfbLog(" mheight: %d mm\n", (int) rev->mheight); rfbLog("\n"); rfbLog("check_xrandr_event: previous WxH: %dx%d\n", wdpy_x, wdpy_y); } if (wdpy_x == rev->width && wdpy_y == rev->height && xrandr_rotation == (int) rev->rotation) { rfbLog("check_xrandr_event: no change detected.\n"); do_change = 0; if (! xrandr) { rfbLog("check_xrandr_event: " "enabling full XRANDR trapping anyway.\n"); xrandr = 1; } } else { do_change = 1; if (! xrandr) { rfbLog("check_xrandr_event: Resize; " "enabling full XRANDR trapping.\n"); xrandr = 1; } } xrandr_width = rev->width; xrandr_height = rev->height; xrandr_timestamp = rev->timestamp; xrandr_cfg_time = rev->config_timestamp; xrandr_rotation = (int) rev->rotation; if (! qout) rfbLog("check_xrandr_event: updating config...\n"); XRRUpdateConfiguration(&xev); if (do_change) { /* under do_change caller normally returns before its X_UNLOCK */ X_UNLOCK; handle_xrandr_change(rev->width, rev->height); } if (qout) { return do_change; } rfbLog("check_xrandr_event: current WxH: %dx%d\n", XDisplayWidth(dpy, scr), XDisplayHeight(dpy, scr)); rfbLog("check_xrandr_event(): returning control to" " caller...\n"); return do_change; } #else xev.type = 0; #endif return 0; }
static void output(rfbScreenInfoPtr s,char* line) { rfbDoCopyRect(s,0,0,width,height-lineHeight,0,-lineHeight); rfbDrawString(s,&default8x16Font,10,lineY,line,0x01); rfbLog("%s\n",line); }
void HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) { int n = 0; char* pBuf = NULL; rfbClientToServerTightMsg msg; memset(&msg, 0, sizeof(rfbClientToServerTightMsg)); if(cl == NULL) { rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadDataMsg-1)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } msg.fud.realSize = Swap16IfLE(msg.fud.realSize); msg.fud.compressedSize = Swap16IfLE(msg.fud.compressedSize); if((msg.fud.realSize == 0) && (msg.fud.compressedSize == 0)) { if((n = rfbReadExact(cl, (char*)&(rtcp->rcft.rcfu.mTime), sizeof(unsigned long))) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } FileUpdateComplete(cl, rtcp); return; } pBuf = (char*) calloc(msg.fud.compressedSize, sizeof(char)); if(pBuf == NULL) { rfbLog("File [%s]: Method [%s]: Memory alloc failed\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, pBuf, msg.fud.compressedSize)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); if(pBuf != NULL) { free(pBuf); pBuf = NULL; } return; } if(msg.fud.compressedLevel != 0) { FileTransferMsg ftm; memset(&ftm, 0, sizeof(FileTransferMsg)); ftm = GetFileUploadCompressedLevelErrMsg(); if((ftm.data != NULL) && (ftm.length != 0)) { rfbWriteExact(cl, ftm.data, ftm.length); FreeFileTransferMsg(ftm); } CloseUndoneFileTransfer(cl, rtcp); if(pBuf != NULL) { free(pBuf); pBuf = NULL; } return; } rtcp->rcft.rcfu.fSize = msg.fud.compressedSize; HandleFileUploadWrite(cl, rtcp, pBuf); if(pBuf != NULL) { free(pBuf); pBuf = NULL; } }
void HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) { int n = 0; char* reason = NULL; rfbClientToServerTightMsg msg; memset(&msg, 0, sizeof(rfbClientToServerTightMsg)); if(cl == NULL) { rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadFailedMsg-1)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); return; } msg.fuf.reasonLen = Swap16IfLE(msg.fuf.reasonLen); if(msg.fuf.reasonLen == 0) { rfbLog("File [%s]: Method [%s]: reason length received is Zero\n", __FILE__, __FUNCTION__); return; } reason = (char*) calloc(msg.fuf.reasonLen + 1, sizeof(char)); if(reason == NULL) { rfbLog("File [%s]: Method [%s]: Memory alloc failed\n", __FILE__, __FUNCTION__); return; } if((n = rfbReadExact(cl, reason, msg.fuf.reasonLen)) <= 0) { if (n < 0) rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); if(reason != NULL) { free(reason); reason = NULL; } return; } rfbLog("File [%s]: Method [%s]: File Upload Failed Request received:" " reason <%s>\n", __FILE__, __FUNCTION__, reason); CloseUndoneFileTransfer(cl, rtcp); if(reason != NULL) { free(reason); reason = NULL; } }
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); }