summaryrefslogtreecommitdiffstats
path: root/libvncserver/tightvnc-filetransfer/rfbtightserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvncserver/tightvnc-filetransfer/rfbtightserver.c')
-rw-r--r--libvncserver/tightvnc-filetransfer/rfbtightserver.c506
1 files changed, 506 insertions, 0 deletions
diff --git a/libvncserver/tightvnc-filetransfer/rfbtightserver.c b/libvncserver/tightvnc-filetransfer/rfbtightserver.c
new file mode 100644
index 0000000..825fce0
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/rfbtightserver.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 25th August 2005
+ */
+
+
+#include <rfb/rfb.h>
+#include "rfbtightproto.h"
+#include "handlefiletransferrequest.h"
+
+/*
+ * Get my data!
+ *
+ * This gets the extension specific data from the client structure. If
+ * the data is not found, the client connection is closed, a complaint
+ * is logged, and NULL is returned.
+ */
+
+extern rfbProtocolExtension tightVncFileTransferExtension;
+
+rfbTightClientPtr rfbGetTightClientData(rfbClientPtr cl)
+{
+ rfbExtensionData* data = cl->extensions;
+
+ while(data && data->extension != &tightVncFileTransferExtension)
+ data = data->next;
+
+ if(data == NULL) {
+ rfbLog("TightVNC enabled, but client data missing?!\n");
+ rfbCloseClient(cl);
+ return NULL;
+ }
+
+ return (rfbTightClientPtr)data->data;
+}
+
+/*
+ * Send the authentication challenge.
+ */
+
+static void
+rfbVncAuthSendChallenge(cl)
+ rfbClientPtr cl;
+{
+
+ // 4 byte header is alreay sent. Which is rfbSecTypeVncAuth (same as rfbVncAuth). Just send the challenge.
+ rfbRandomBytes(cl->authChallenge);
+ if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
+ rfbLogPerror("rfbAuthNewClient: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ /* Dispatch client input to rfbVncAuthProcessResponse. */
+ /* This methos is defined in auth.c file */
+ rfbAuthProcessClientMessage(cl);
+
+}
+
+/*
+ * Read client's preferred authentication type (protocol 3.7t).
+ */
+
+void
+rfbProcessClientAuthType(cl)
+ rfbClientPtr cl;
+{
+ uint32_t auth_type;
+ int n, i;
+ rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
+
+ if(rtcp == NULL)
+ return;
+
+ /* Read authentication type selected by the client. */
+ n = rfbReadExact(cl, (char *)&auth_type, sizeof(auth_type));
+ if (n <= 0) {
+ if (n == 0)
+ rfbLog("rfbProcessClientAuthType: client gone\n");
+ else
+ rfbLogPerror("rfbProcessClientAuthType: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ auth_type = Swap32IfLE(auth_type);
+
+ /* Make sure it was present in the list sent by the server. */
+ for (i = 0; i < rtcp->nAuthCaps; i++) {
+ if (auth_type == rtcp->authCaps[i])
+ break;
+ }
+ if (i >= rtcp->nAuthCaps) {
+ rfbLog("rfbProcessClientAuthType: "
+ "wrong authentication type requested\n");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ switch (auth_type) {
+ case rfbAuthNone:
+ /* Dispatch client input to rfbProcessClientInitMessage. */
+ cl->state = RFB_INITIALISATION;
+ break;
+ case rfbAuthVNC:
+ rfbVncAuthSendChallenge(cl);
+ break;
+ default:
+ rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
+ rfbCloseClient(cl);
+ }
+}
+
+
+/*
+ * Read tunneling type requested by the client (protocol 3.7t).
+ * NOTE: Currently, we don't support tunneling, and this function
+ * can never be called.
+ */
+
+void
+rfbProcessClientTunnelingType(cl)
+ rfbClientPtr cl;
+{
+ /* If we were called, then something's really wrong. */
+ rfbLog("rfbProcessClientTunnelingType: not implemented\n");
+ rfbCloseClient(cl);
+ return;
+}
+
+
+/*
+ * Send the list of our authentication capabilities to the client
+ * (protocol 3.7t).
+ */
+
+static void
+rfbSendAuthCaps(cl)
+ rfbClientPtr cl;
+{
+ rfbBool authRequired;
+ rfbAuthenticationCapsMsg caps;
+ rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
+ int count = 0;
+ rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
+
+ if(rtcp == NULL)
+ return;
+
+ if (cl->screen->authPasswdData && !cl->reverseConnection) {
+ // chk if this condition is valid or not.
+ SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
+ rtcp->authCaps[count++] = rfbAuthVNC;
+ }
+
+ rtcp->nAuthCaps = count;
+ caps.nAuthTypes = Swap32IfLE((uint32_t)count);
+ if (rfbWriteExact(cl, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
+ rfbLogPerror("rfbSendAuthCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if (count) {
+ if (rfbWriteExact(cl, (char *)&caplist[0],
+ count * sz_rfbCapabilityInfo) < 0) {
+ rfbLogPerror("rfbSendAuthCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+ /* Dispatch client input to rfbProcessClientAuthType. */
+ /* Call the function for authentication from here */
+ rfbProcessClientAuthType(cl);
+ } else {
+ /* Dispatch client input to rfbProcessClientInitMessage. */
+ cl->state = RFB_INITIALISATION;
+ }
+}
+
+
+
+
+
+/*
+ * Send the list of our tunneling capabilities (protocol 3.7t).
+ */
+
+static void
+rfbSendTunnelingCaps(cl)
+ rfbClientPtr cl;
+{
+ rfbTunnelingCapsMsg caps;
+ uint32_t nTypes = 0; /* we don't support tunneling yet */
+
+ 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);
+ }
+}
+
+
+
+/*
+ * rfbSendInteractionCaps is called after sending the server
+ * initialisation message, only if TightVNC protocol extensions were
+ * enabled (protocol 3.7t). In this function, we send the lists of
+ * supported protocol messages and encodings.
+ */
+
+/* Update these constants on changing capability lists below! */
+/* Values updated for FTP */
+#define N_SMSG_CAPS 4
+#define N_CMSG_CAPS 6
+#define N_ENC_CAPS 12
+
+void
+rfbSendInteractionCaps(cl)
+ rfbClientPtr cl;
+{
+ rfbInteractionCapsMsg intr_caps;
+ rfbCapabilityInfo smsg_list[N_SMSG_CAPS];
+ rfbCapabilityInfo cmsg_list[N_CMSG_CAPS];
+ rfbCapabilityInfo enc_list[N_ENC_CAPS];
+ int i;
+
+ /* Fill in the header structure sent prior to capability lists. */
+ intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
+ intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
+ intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
+ intr_caps.pad = 0;
+
+ /* Supported server->client message types. */
+ /* For file transfer support: */
+ i = 0;
+ if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
+ SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor);
+ SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor);
+ SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor);
+ SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor);
+ if (i != N_SMSG_CAPS) {
+ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
+ rfbCloseClient(cl);
+ return;
+ }
+ }
+
+ /* Supported client->server message types. */
+ /* For file transfer support: */
+ i = 0;
+ if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
+ SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor);
+ if (i != N_CMSG_CAPS) {
+ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
+ rfbCloseClient(cl);
+ return;
+ }
+ }
+
+ /* Encoding types. */
+ i = 0;
+ SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor);
+ if (i != N_ENC_CAPS) {
+ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ /* Send header and capability lists */
+ if (rfbWriteExact(cl, (char *)&intr_caps,
+ sz_rfbInteractionCapsMsg) < 0 ||
+ rfbWriteExact(cl, (char *)&smsg_list[0],
+ sz_rfbCapabilityInfo * N_SMSG_CAPS) < 0 ||
+ rfbWriteExact(cl, (char *)&cmsg_list[0],
+ sz_rfbCapabilityInfo * N_CMSG_CAPS) < 0 ||
+ rfbWriteExact(cl, (char *)&enc_list[0],
+ sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
+ rfbLogPerror("rfbSendInteractionCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ /* Dispatch client input to rfbProcessClientNormalMessage(). */
+ cl->state = RFB_NORMAL;
+}
+
+
+
+rfbBool
+rfbTightExtensionInit(cl, data)
+rfbClientPtr cl;
+void** data;
+{
+
+ rfbSendInteractionCaps(cl);
+
+ return TRUE;
+}
+
+static rfbBool
+handleMessage(rfbClientPtr cl,
+ const char* messageName,
+ void (*handler)(rfbClientPtr cl, rfbTightClientPtr data))
+{
+ rfbTightClientPtr data;
+
+ rfbLog("%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;
+}
+
+rfbBool
+rfbTightExtensionMsgHandler(cl, data, msg)
+struct _rfbClientRec* cl;
+void* data;
+const rfbClientToServerMsg* msg;
+{
+ switch (msg->type) {
+
+ case rfbFileListRequest:
+
+ return handleMessage(cl, "rfbFileListRequest", HandleFileListRequest);
+
+ case rfbFileDownloadRequest:
+
+ return handleMessage(cl, "rfbFileDownloadRequest", HandleFileDownloadRequest);
+
+ case rfbFileUploadRequest:
+
+ return handleMessage(cl, "rfbFileUploadRequest", HandleFileUploadRequest);
+
+ case rfbFileUploadData:
+
+ return handleMessage(cl, "rfbFileUploadDataRequest", HandleFileUploadDataRequest);
+
+ case rfbFileDownloadCancel:
+
+ return handleMessage(cl, "rfbFileDownloadCancelRequest", HandleFileDownloadCancelRequest);
+
+ case rfbFileUploadFailed:
+
+ return handleMessage(cl, "rfbFileUploadFailedRequest", HandleFileUploadFailedRequest);
+
+ case rfbFileCreateDirRequest:
+
+ return handleMessage(cl, "rfbFileCreateDirRequest", HandleFileCreateDirRequest);
+
+ default:
+
+ rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
+ msg->type);
+
+ /*
+
+ // We shouldn't close the connection here for unhandled msg, it should be left to libvncserver.
+ rfbLog(" ... closing connection\n");
+ rfbCloseClient(cl);
+
+ */
+
+ return FALSE;
+
+ }
+}
+
+
+void
+rfbTightExtensionClientClose(rfbClientPtr cl, void* data) {
+
+ if(data != NULL)
+ free(data);
+
+}
+
+void
+rfbTightUsage(void) {
+ fprintf(stderr, "\nlibvncserver-tight-extension options:\n");
+ fprintf(stderr, "-disablefiletransfer disable file transfer\n");
+ fprintf(stderr, "-ftproot string set ftp root\n");
+ fprintf(stderr,"\n");
+}
+
+int
+rfbTightProcessArg(int argc, char *argv[]) {
+
+ InitFileTransfer();
+
+ if(argc<1)
+ return 0;
+
+ if (strcmp(argv[0], "-ftproot") == 0) { /* -ftproot string */
+ if (2 > argc) {
+ return 0;
+ }
+ rfbLog("ftproot is set to <%s>\n", argv[1]);
+ if(SetFtpRoot(argv[1]) == FALSE) {
+ rfbLog("ERROR:: Path specified for ftproot in invalid\n");
+ return 0;
+ }
+ return 2;
+ } else if (strcmp(argv[0], "-disablefiletransfer") == 0) {
+ EnableFileTransfer(FALSE);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This method should be registered to libvncserver to handle rfbSecTypeTight security type.
+ */
+void
+rfbHandleSecTypeTight(rfbClientPtr cl) {
+
+ rfbTightClientPtr rtcp = (rfbTightClientPtr) malloc(sizeof(rfbTightClientRec));
+
+ if(rtcp == NULL) {
+ // Error condition close socket
+ rfbLog("Memory error has occured while handling Tight security type... closing connection.\n");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ memset(rtcp, 0, sizeof(rfbTightClientRec));
+ rtcp->rcft.rcfd.downloadFD = -1;
+ rtcp->rcft.rcfu.uploadFD = -1;
+ rfbEnableExtension(cl, &tightVncFileTransferExtension, rtcp);
+
+ rfbSendTunnelingCaps(cl);
+
+}
+
+rfbProtocolExtension tightVncFileTransferExtension = {
+ NULL,
+ rfbTightExtensionInit,
+ rfbTightExtensionMsgHandler,
+ rfbTightExtensionClientClose,
+ rfbTightUsage,
+ rfbTightProcessArg,
+ NULL
+};
+
+static rfbSecurityHandler tightVncSecurityHandler = {
+ rfbSecTypeTight,
+ rfbHandleSecTypeTight,
+ NULL
+};
+
+void rfbRegisterTightVNCFileTransferExtension() {
+ rfbRegisterProtocolExtension(&tightVncFileTransferExtension);
+ rfbRegisterSecurityHandler(&tightVncSecurityHandler);
+}
+
+