|
|
|
@ -1,8 +1,8 @@
|
|
|
|
|
/**
|
|
|
|
|
* xrdp: A Remote Desktop Protocol server.
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) Thomas Goddard 2012
|
|
|
|
|
* Copyright (C) Jay Sorg 2012
|
|
|
|
|
* Copyright (C) Laxmikant Rashinkar 2012
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
@ -17,8 +17,6 @@
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* do not use os_calls in here */
|
|
|
|
|
|
|
|
|
|
#define LOG_LEVEL 1
|
|
|
|
|
#define LLOG(_level, _args) \
|
|
|
|
|
do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0)
|
|
|
|
@ -29,6 +27,7 @@
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
@ -40,69 +39,31 @@
|
|
|
|
|
|
|
|
|
|
struct wts_obj
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
int status;
|
|
|
|
|
char name[8];
|
|
|
|
|
char dname[128];
|
|
|
|
|
int display_num;
|
|
|
|
|
int flags;
|
|
|
|
|
int fd;
|
|
|
|
|
int status;
|
|
|
|
|
char name[8];
|
|
|
|
|
char dname[128];
|
|
|
|
|
int display_num;
|
|
|
|
|
uint32_t flags;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
get_display_num_from_display(char *display_text)
|
|
|
|
|
{
|
|
|
|
|
int index;
|
|
|
|
|
int mode;
|
|
|
|
|
int host_index;
|
|
|
|
|
int disp_index;
|
|
|
|
|
int scre_index;
|
|
|
|
|
char host[256];
|
|
|
|
|
char disp[256];
|
|
|
|
|
char scre[256];
|
|
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
|
host_index = 0;
|
|
|
|
|
disp_index = 0;
|
|
|
|
|
scre_index = 0;
|
|
|
|
|
mode = 0;
|
|
|
|
|
/* helper functions used by WTSxxx API - do not invoke directly */
|
|
|
|
|
static int get_display_num_from_display(char *display_text);
|
|
|
|
|
static int send_init(struct wts_obj *wts);
|
|
|
|
|
static int can_send(int sck, int millis);
|
|
|
|
|
static int can_recv(int sck, int millis);
|
|
|
|
|
|
|
|
|
|
while (display_text[index] != 0)
|
|
|
|
|
{
|
|
|
|
|
if (display_text[index] == ':')
|
|
|
|
|
{
|
|
|
|
|
mode = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (display_text[index] == '.')
|
|
|
|
|
{
|
|
|
|
|
mode = 2;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == 0)
|
|
|
|
|
{
|
|
|
|
|
host[host_index] = display_text[index];
|
|
|
|
|
host_index++;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == 1)
|
|
|
|
|
{
|
|
|
|
|
disp[disp_index] = display_text[index];
|
|
|
|
|
disp_index++;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == 2)
|
|
|
|
|
{
|
|
|
|
|
scre[scre_index] = display_text[index];
|
|
|
|
|
scre_index++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host[host_index] = 0;
|
|
|
|
|
disp[disp_index] = 0;
|
|
|
|
|
scre[scre_index] = 0;
|
|
|
|
|
return atoi(disp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*
|
|
|
|
|
* Opens a handle to the server end of a specified virtual channel - this
|
|
|
|
|
* call is deprecated - use WTSVirtualChannelOpenEx() instead
|
|
|
|
|
*
|
|
|
|
|
* @param hServer
|
|
|
|
|
* @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
|
|
|
|
|
* @param pVirtualName - virtual channel name when using SVC
|
|
|
|
|
* - name of endpoint listener when using DVC
|
|
|
|
|
*
|
|
|
|
|
* @return a valid pointer on success, NULL on error
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void *
|
|
|
|
|
WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
|
|
|
|
|
const char *pVirtualName)
|
|
|
|
@ -115,98 +76,34 @@ WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
|
|
|
|
|
return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
can_send(int sck, int millis)
|
|
|
|
|
{
|
|
|
|
|
struct timeval time;
|
|
|
|
|
fd_set wfds;
|
|
|
|
|
int select_rv;
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&wfds);
|
|
|
|
|
FD_SET(sck, &wfds);
|
|
|
|
|
time.tv_sec = millis / 1000;
|
|
|
|
|
time.tv_usec = (millis * 1000) % 1000000;
|
|
|
|
|
select_rv = select(sck + 1, 0, &wfds, 0, &time);
|
|
|
|
|
|
|
|
|
|
if (select_rv > 0)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
can_recv(int sck, int millis)
|
|
|
|
|
{
|
|
|
|
|
struct timeval time;
|
|
|
|
|
fd_set rfds;
|
|
|
|
|
int select_rv;
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
|
FD_SET(sck, &rfds);
|
|
|
|
|
time.tv_sec = millis / 1000;
|
|
|
|
|
time.tv_usec = (millis * 1000) % 1000000;
|
|
|
|
|
select_rv = select(sck + 1, &rfds, 0, 0, &time);
|
|
|
|
|
|
|
|
|
|
if (select_rv > 0)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
send_init(struct wts_obj *wts)
|
|
|
|
|
{
|
|
|
|
|
char initmsg[64];
|
|
|
|
|
|
|
|
|
|
memset(initmsg, 0, 64);
|
|
|
|
|
strncpy(initmsg, wts->name, 8);
|
|
|
|
|
initmsg[16] = (wts->flags >> 0) & 0xff;
|
|
|
|
|
initmsg[17] = (wts->flags >> 8) & 0xff;
|
|
|
|
|
initmsg[18] = (wts->flags >> 16) & 0xff;
|
|
|
|
|
initmsg[19] = (wts->flags >> 24) & 0xff;
|
|
|
|
|
LLOGLN(10, ("send_init: sending %s", initmsg));
|
|
|
|
|
|
|
|
|
|
if (!can_send(wts->fd, 500))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (send(wts->fd, initmsg, 64, 0) != 64)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LLOGLN(10, ("send_init: send ok!"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*
|
|
|
|
|
* Opens a handle to the server end of a specified virtual channel
|
|
|
|
|
*
|
|
|
|
|
* @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
|
|
|
|
|
* @param pVirtualName - virtual channel name when using SVC
|
|
|
|
|
* - name of endpoint listener when using DVC
|
|
|
|
|
* @param flags - type of channel and channel priority if DVC
|
|
|
|
|
*
|
|
|
|
|
* @return a valid pointer on success, NULL on error
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void *
|
|
|
|
|
WTSVirtualChannelOpenEx(unsigned int SessionId,
|
|
|
|
|
const char *pVirtualName,
|
|
|
|
|
WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
|
|
|
|
|
unsigned int flags)
|
|
|
|
|
{
|
|
|
|
|
struct wts_obj *wts;
|
|
|
|
|
char *display_text;
|
|
|
|
|
struct sockaddr_un s;
|
|
|
|
|
int bytes;
|
|
|
|
|
unsigned long llong;
|
|
|
|
|
struct wts_obj *wts;
|
|
|
|
|
char *display_text;
|
|
|
|
|
int bytes;
|
|
|
|
|
unsigned long llong;
|
|
|
|
|
struct sockaddr_un s;
|
|
|
|
|
|
|
|
|
|
if (SessionId != WTS_CURRENT_SESSION)
|
|
|
|
|
{
|
|
|
|
|
LLOGLN(0, ("WTSVirtualChannelOpenEx: SessionId bad"));
|
|
|
|
|
LLOGLN(0, ("WTSVirtualChannelOpenEx: bad SessionId"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wts = (struct wts_obj *)malloc(sizeof(struct wts_obj));
|
|
|
|
|
memset(wts, 0, sizeof(struct wts_obj));
|
|
|
|
|
wts = (struct wts_obj *) calloc(1, sizeof(struct wts_obj));
|
|
|
|
|
|
|
|
|
|
wts->fd = -1;
|
|
|
|
|
wts->flags = flags;
|
|
|
|
|
display_text = getenv("DISPLAY");
|
|
|
|
@ -216,37 +113,40 @@ WTSVirtualChannelOpenEx(unsigned int SessionId,
|
|
|
|
|
wts->display_num = get_display_num_from_display(display_text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wts->display_num > 0)
|
|
|
|
|
if (wts->display_num <= 0)
|
|
|
|
|
{
|
|
|
|
|
wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
|
/* set non blocking */
|
|
|
|
|
llong = fcntl(wts->fd, F_GETFL);
|
|
|
|
|
llong = llong | O_NONBLOCK;
|
|
|
|
|
fcntl(wts->fd, F_SETFL, llong);
|
|
|
|
|
/* connect to session chansrv */
|
|
|
|
|
memset(&s, 0, sizeof(struct sockaddr_un));
|
|
|
|
|
s.sun_family = AF_UNIX;
|
|
|
|
|
bytes = sizeof(s.sun_path);
|
|
|
|
|
snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num);
|
|
|
|
|
s.sun_path[bytes - 1] = 0;
|
|
|
|
|
bytes = sizeof(struct sockaddr_un);
|
|
|
|
|
|
|
|
|
|
if (connect(wts->fd, (struct sockaddr *)&s, bytes) == 0)
|
|
|
|
|
{
|
|
|
|
|
LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
|
|
|
|
|
strncpy(wts->name, pVirtualName, 8);
|
|
|
|
|
|
|
|
|
|
/* wait for connection to complete and send init */
|
|
|
|
|
if (send_init(wts) == 0)
|
|
|
|
|
{
|
|
|
|
|
/* all ok */
|
|
|
|
|
wts->status = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LLOGLN(0, ("WTSVirtualChannelOpenEx: fatal errror; display is 0"));
|
|
|
|
|
free(wts);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
/* we use unix domain socket to communicate with chansrv */
|
|
|
|
|
wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
|
|
|
|
|
|
/* set non blocking */
|
|
|
|
|
llong = fcntl(wts->fd, F_GETFL);
|
|
|
|
|
llong = llong | O_NONBLOCK;
|
|
|
|
|
fcntl(wts->fd, F_SETFL, llong);
|
|
|
|
|
|
|
|
|
|
/* connect to chansrv session */
|
|
|
|
|
memset(&s, 0, sizeof(struct sockaddr_un));
|
|
|
|
|
s.sun_family = AF_UNIX;
|
|
|
|
|
bytes = sizeof(s.sun_path);
|
|
|
|
|
snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num);
|
|
|
|
|
s.sun_path[bytes - 1] = 0;
|
|
|
|
|
bytes = sizeof(struct sockaddr_un);
|
|
|
|
|
|
|
|
|
|
if (connect(wts->fd, (struct sockaddr *) &s, bytes) == 0)
|
|
|
|
|
{
|
|
|
|
|
LLOGLN(0, ("WTSVirtualChannelOpenEx: display is 0"));
|
|
|
|
|
LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
|
|
|
|
|
strncpy(wts->name, pVirtualName, 8);
|
|
|
|
|
|
|
|
|
|
/* wait for connection to complete and send init */
|
|
|
|
|
if (send_init(wts) == 0)
|
|
|
|
|
{
|
|
|
|
|
/* all ok */
|
|
|
|
|
wts->status = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return wts;
|
|
|
|
@ -312,7 +212,7 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
|
|
|
|
unsigned int *pBytesRead)
|
|
|
|
|
{
|
|
|
|
|
struct wts_obj *wts;
|
|
|
|
|
int error;
|
|
|
|
|
int rv;
|
|
|
|
|
int lerrno;
|
|
|
|
|
|
|
|
|
|
wts = (struct wts_obj *)hChannelHandle;
|
|
|
|
@ -329,9 +229,9 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
|
|
|
|
|
|
|
|
|
if (can_recv(wts->fd, TimeOut))
|
|
|
|
|
{
|
|
|
|
|
error = recv(wts->fd, Buffer, BufferSize, 0);
|
|
|
|
|
rv = recv(wts->fd, Buffer, BufferSize, 0);
|
|
|
|
|
|
|
|
|
|
if (error == -1)
|
|
|
|
|
if (rv == -1)
|
|
|
|
|
{
|
|
|
|
|
lerrno = errno;
|
|
|
|
|
|
|
|
|
@ -341,16 +241,15 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
|
|
|
|
*pBytesRead = 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (error == 0)
|
|
|
|
|
else if (rv == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (error > 0)
|
|
|
|
|
else if (rv > 0)
|
|
|
|
|
{
|
|
|
|
|
*pBytesRead = error;
|
|
|
|
|
*pBytesRead = rv;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -419,3 +318,148 @@ WTSFreeMemory(void *pMemory)
|
|
|
|
|
free(pMemory);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
** **
|
|
|
|
|
** **
|
|
|
|
|
** Helper functions used by WTSxxx API - do not invoke directly **
|
|
|
|
|
** **
|
|
|
|
|
** **
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* check if socket is in a writable state - i.e will not block on write
|
|
|
|
|
*
|
|
|
|
|
* @param sck socket to check
|
|
|
|
|
* @param millis timeout value in milliseconds
|
|
|
|
|
*
|
|
|
|
|
* @return 0 if write will block
|
|
|
|
|
* @return 1 if write will not block
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
can_send(int sck, int millis)
|
|
|
|
|
{
|
|
|
|
|
struct timeval time;
|
|
|
|
|
fd_set wfds;
|
|
|
|
|
int select_rv;
|
|
|
|
|
|
|
|
|
|
/* setup for a select call */
|
|
|
|
|
FD_ZERO(&wfds);
|
|
|
|
|
FD_SET(sck, &wfds);
|
|
|
|
|
time.tv_sec = millis / 1000;
|
|
|
|
|
time.tv_usec = (millis * 1000) % 1000000;
|
|
|
|
|
|
|
|
|
|
/* check if it is ok to write to specified socket */
|
|
|
|
|
select_rv = select(sck + 1, 0, &wfds, 0, &time);
|
|
|
|
|
|
|
|
|
|
return (select_rv > 0) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
can_recv(int sck, int millis)
|
|
|
|
|
{
|
|
|
|
|
struct timeval time;
|
|
|
|
|
fd_set rfds;
|
|
|
|
|
int select_rv;
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
|
FD_SET(sck, &rfds);
|
|
|
|
|
time.tv_sec = millis / 1000;
|
|
|
|
|
time.tv_usec = (millis * 1000) % 1000000;
|
|
|
|
|
select_rv = select(sck + 1, &rfds, 0, 0, &time);
|
|
|
|
|
|
|
|
|
|
if (select_rv > 0)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
send_init(struct wts_obj *wts)
|
|
|
|
|
{
|
|
|
|
|
char initmsg[64];
|
|
|
|
|
|
|
|
|
|
memset(initmsg, 0, 64);
|
|
|
|
|
|
|
|
|
|
/* insert channel name */
|
|
|
|
|
strncpy(initmsg, wts->name, 8);
|
|
|
|
|
|
|
|
|
|
/* insert open mode flags */
|
|
|
|
|
initmsg[16] = (wts->flags >> 0) & 0xff;
|
|
|
|
|
initmsg[17] = (wts->flags >> 8) & 0xff;
|
|
|
|
|
initmsg[18] = (wts->flags >> 16) & 0xff;
|
|
|
|
|
initmsg[19] = (wts->flags >> 24) & 0xff;
|
|
|
|
|
|
|
|
|
|
if (!can_send(wts->fd, 500))
|
|
|
|
|
{
|
|
|
|
|
LLOGLN(10, ("send_init: send() will block!"));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (send(wts->fd, initmsg, 64, 0) != 64)
|
|
|
|
|
{
|
|
|
|
|
LLOGLN(10, ("send_init: send() failed!"));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LLOGLN(10, ("send_init: sent ok!"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
static int
|
|
|
|
|
get_display_num_from_display(char *display_text)
|
|
|
|
|
{
|
|
|
|
|
int index;
|
|
|
|
|
int mode;
|
|
|
|
|
int host_index;
|
|
|
|
|
int disp_index;
|
|
|
|
|
int scre_index;
|
|
|
|
|
char host[256];
|
|
|
|
|
char disp[256];
|
|
|
|
|
char scre[256];
|
|
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
|
host_index = 0;
|
|
|
|
|
disp_index = 0;
|
|
|
|
|
scre_index = 0;
|
|
|
|
|
mode = 0;
|
|
|
|
|
|
|
|
|
|
while (display_text[index] != 0)
|
|
|
|
|
{
|
|
|
|
|
if (display_text[index] == ':')
|
|
|
|
|
{
|
|
|
|
|
mode = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (display_text[index] == '.')
|
|
|
|
|
{
|
|
|
|
|
mode = 2;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == 0)
|
|
|
|
|
{
|
|
|
|
|
host[host_index] = display_text[index];
|
|
|
|
|
host_index++;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == 1)
|
|
|
|
|
{
|
|
|
|
|
disp[disp_index] = display_text[index];
|
|
|
|
|
disp_index++;
|
|
|
|
|
}
|
|
|
|
|
else if (mode == 2)
|
|
|
|
|
{
|
|
|
|
|
scre[scre_index] = display_text[index];
|
|
|
|
|
scre_index++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host[host_index] = 0;
|
|
|
|
|
disp[disp_index] = 0;
|
|
|
|
|
scre[scre_index] = 0;
|
|
|
|
|
return atoi(disp);
|
|
|
|
|
}
|
|
|
|
|