Merge branch 'devel' into v0.9

This commit is contained in:
Koichiro IWAO 2018-09-25 15:10:32 +09:00
commit a0edfad3df
No known key found for this signature in database
GPG Key ID: 9F72CDBC01BF10EB
22 changed files with 102 additions and 1373 deletions

2
.gitignore vendored
View File

@ -43,4 +43,4 @@ sesman/sesman.ini
stamp-h1
xrdp/xrdp
xrdp/xrdp.ini
configure_params.h
xrdp_configure_options.h

27
NEWS.md
View File

@ -1,3 +1,30 @@
# Release notes for xrdp v0.9.8 (2018/09/25)
## Deprecation notice
We removed TLSv1 and TLSv1.1 from the default config. The current default is TLSv1.2
and TLSv1.3. Users can whenever re-enable these early TLS versions by editing xrdp.
To use TLSv1.3, OpenSSL or LibreSSL must support TLSv1.3. You can know the OpenSSL
or LibreSSL version by `xrdp --version` command that compiled with xrdp.
## Other topics
Pulseaudio modules has been removed from xrdp source tree since it is actually
independent and not part of xrdp. The repository has been moved to:
https://github.com/neutrinolabs/pulseaudio-module-xrdp
If you want to use audio redirection, make sure install the module separately.
## New features
* Add TLSv1.3 support #1193
## Bug fixes
* Ensure unmount redirected drive on fatal X error #1140
## Other changes
* Show more helpful message if xrdp-dis failed #1206
* Pass pulse socket name via environment variable #1198
* Fix xrdp's log path in man page #1168
# Release notes for xrdp v0.9.7 (2018/06/29)
## Deprecation notice

View File

@ -2,7 +2,7 @@
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp)
![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
*Current Version:* 0.9.7
*Current Version:* 0.9.8
# xrdp - an open source RDP server

View File

@ -1004,8 +1004,23 @@ ssl_get_protocols_from_string(const char *str, long *ssl_protocols)
#endif
#if defined(SSL_OP_NO_TLSv1_2)
protocols |= SSL_OP_NO_TLSv1_2;
#endif
#if defined(SSL_OP_NO_TLSv1_3)
protocols |= SSL_OP_NO_TLSv1_3;
#endif
bad_protocols = protocols;
if (g_pos(str, ",TLSv1.3,") >= 0)
{
#if defined(SSL_OP_NO_TLSv1_3)
log_message(LOG_LEVEL_DEBUG, "TLSv1.3 enabled");
protocols &= ~SSL_OP_NO_TLSv1_3;
#else
log_message(LOG_LEVEL_WARNING,
"TLSv1.3 enabled by config, "
"but not supported by system OpenSSL");
rv |= (1 << 6);
#endif
}
if (g_pos(str, ",TLSv1.2,") >= 0)
{
#if defined(SSL_OP_NO_TLSv1_2)

View File

@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script
AC_PREREQ(2.65)
AC_INIT([xrdp], [0.9.7], [xrdp-devel@googlegroups.com])
AC_INIT([xrdp], [0.9.8], [xrdp-devel@googlegroups.com])
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
AM_INIT_AUTOMAKE([1.7.2 foreign])
AC_CONFIG_MACRO_DIR([m4])

View File

@ -144,7 +144,7 @@ Negotiate these security methods with clients.
.RE
.TP
\fBssl_protocols\fP=\fI[SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2]\fP
\fBssl_protocols\fP=\fI[SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3]\fP
Enables the specified SSL/TLS protocols. Each value should be separated by comma.
SSLv2 is always disabled. At least one protocol should be given to accept TLS connections.
This parameter is effective only if \fBsecurity_layer\fP is set to \fBtls\fP or \fBnegotiate\fP.
@ -206,7 +206,7 @@ The highest value is 255 (hex FF).
The following parameters can be used in the \fB[Logging]\fR section:
.TP
\fBLogFile\fR=\fI@localstatedir@/log/sesman.log\fR
\fBLogFile\fR=\fI@localstatedir@/log/xrdp.log\fR
This options contains the path to logfile. It can be either absolute or relative.\fR
.TP

View File

@ -1,7 +1,6 @@
EXTRA_DIST = \
clipboard-notes.txt \
pcsc \
pulse \
wave-format-server.txt
AM_CPPFLAGS = \

View File

@ -1278,6 +1278,16 @@ segfault_signal_handler(int sig)
exit(0);
}
/*****************************************************************************/
static void
x_server_fatal_handler(void)
{
LOGM((LOG_LEVEL_INFO, "xserver_fatal_handler: entered......."));
/* At this point the X server has gone away. Dont make any X calls. */
xfuse_deinit();
exit(0);
}
/*****************************************************************************/
static int
get_display_num_from_display(char *display_text)
@ -1576,6 +1586,9 @@ main(int argc, char **argv)
g_signal_child_stop(child_signal_handler); /* SIGCHLD */
g_signal_segfault(segfault_signal_handler);
/* Cater for the X server exiting unexpectedly */
xcommon_set_x_server_fatal_handler(x_server_fatal_handler);
LOGM((LOG_LEVEL_INFO, "main: DISPLAY env var set to %s", display_text));
if (g_display_num == 0)

View File

@ -1 +0,0 @@
!Makefile

View File

@ -1,18 +0,0 @@
#
# build xrdp pulseaudio modules
#
# change this to your pulseaudio source directory
PULSE_DIR = /tmp/pulseaudio-10.0
CFLAGS = -Wall -O2 -I$(PULSE_DIR) -I$(PULSE_DIR)/src -DHAVE_CONFIG_H -fPIC
all: module-xrdp-sink.so module-xrdp-source.so
module-xrdp-sink.so: module-xrdp-sink.o
$(CC) $(LDFLAGS) -shared -o module-xrdp-sink.so module-xrdp-sink.o
module-xrdp-source.so: module-xrdp-source.o
$(CC) $(LDFLAGS) -shared -o module-xrdp-source.so module-xrdp-source.o
clean:
rm -f module-xrdp-sink.o module-xrdp-sink.so module-xrdp-source.o module-xrdp-source.so

View File

@ -1,117 +0,0 @@
The latest version of this document can be found at wiki.
* https://github.com/neutrinolabs/xrdp/wiki/How-to-set-up-audio-redirection
# Overview
xrdp supports audio redirection using PulseAudio, which is a sound system for
POSIX operating systems. Server to client redirection is compliant to Remote
Desktop Procol standard [[MS-RDPEA]](https://msdn.microsoft.com/en-us/library/cc240933.aspx)
but client to server redirection implementation is proprietary. Accordingly,
server to client redirection is available with many of RDP clients including
Microsoft client but client to server redirection requires NeutrinoRDP client,
not available with other clients.
Here is how to build pulseaudio modules for your distro, so you can have audio
support through xrdp.
# Prerequisites
Prepare xrdp source in your home directory. Of course, you can choose another
directory.
cd ~
git clone https://github.com/neutrinolabs/xrdp.git
In this instruction, pulseaudio version is **10.0**. Replace the version number
in this instruction if your environment has different versions. You can find
out your pulseaudio version executing the following command:
pulseaudio --version
# How to build
## Debian 9 / Ubuntu
This instruction also should be applicable to Ubuntu family.
### Prerequisites
Some build tools and package development tools are required. Make sure install
the tools.
apt install build-essential dpkg-dev
### Prepare & build
Install pulseaudio and requisite packages to build pulseaudio.
apt install pulseaudio
apt build-dep pulseaudio
Fetch the pulseaudio source . You'll see `pulseaudio-10.0` directory in your
current directory.
apt source pulseaudio
Enter into the directory and build the pulseaudio package.
cd pulseaudio-10.0
./configure
Finally, let's make. You'll have two .so files `module-xrdp-sink.so` and
`module-xrdp-source.so`.
cd ~/xrdp/sesman/chansrv/pulse
make PULSE_DIR="~/pulseaudio-10.0"
## Other distro
First off, find out your pulseaudio version using `pulseaudio --version`
command. Download the tarball of the pulseaudio version that you have.
* https://freedesktop.org/software/pulseaudio/releases/
After downloading the tarball, extact the tarball and `cd` into the source
directory, then run `./configure`.
wget https://freedesktop.org/software/pulseaudio/releases/pulseaudio-10.0.tar.xz
tar xf pulseaudio-10.0.tar.gz
cd pulseaudio-10.0
./configure
If additional packages are required to run `./configure`, install requisite
packages depending on your environment.
Finally, let's make. You'll have two .so files `module-xrdp-sink.so` and
`module-xrdp-source.so`.
cd ~/xrdp/sesman/chansrv/pulse
make PULSE_DIR="~/pulseaudio-10.0"
# Install
Install process is not distro specific except for install destination. Install
built two .so files into the pulseaudio modules directory. Typically,
`/usr/lib/pulse-10.0/modules` for Debian, `/usr/lib64/pulse-10.0/modules` for
CentOS 7. Other distro might have different path. Find out the right path for
your distro.
Look into the directory with `ls` command. You'll see lots of `module-*.so`
files. There's the place!
cd ~/xrdp/sesman/chansrv/pulse
for f in *.so; do install -s -m 644 $f /usr/lib/pulse-10.0/modules; done
This command is equivalent to following:
install -s -m 644 module-xrdp-sink.so /usr/lib/pulse-10.0/modules
install -s -m 644 module-xrdp-source.so /usr/lib/pulse-10.0/modules
Well done! Pulseaudio modules should be properly built and installed.
# See if it works
To see if it works, run `pavumeter` in the xrdp session. Playback any YouTube
video in Firefox. You'll see "Showing signal levels of **xrdp sink**" and
volume meter moving.

View File

@ -1,29 +0,0 @@
#ifndef MODULE_XRDP_SINK_SYMDEF_H
#define MODULE_XRDP_SINK_SYMDEF_H
#include <pulsecore/core.h>
#include <pulsecore/module.h>
#include <pulsecore/macro.h>
#define pa__init module_xrdp_sink_LTX_pa__init
#define pa__done module_xrdp_sink_LTX_pa__done
#define pa__get_author module_xrdp_sink_LTX_pa__get_author
#define pa__get_description module_xrdp_sink_LTX_pa__get_description
#define pa__get_usage module_xrdp_sink_LTX_pa__get_usage
#define pa__get_version module_xrdp_sink_LTX_pa__get_version
#define pa__get_deprecated module_xrdp_sink_LTX_pa__get_deprecated
#define pa__load_once module_xrdp_sink_LTX_pa__load_once
#define pa__get_n_used module_xrdp_sink_LTX_pa__get_n_used
int pa__init(pa_module*m);
void pa__done(pa_module*m);
int pa__get_n_used(pa_module*m);
const char* pa__get_author(void);
const char* pa__get_description(void);
const char* pa__get_usage(void);
const char* pa__get_version(void);
const char* pa__get_deprecated(void);
pa_bool_t pa__load_once(void);
#endif

View File

@ -1,613 +0,0 @@
/**
* xrdp: A Remote Desktop Protocol server.
* pulse sink
*
* Copyright (C) Jay Sorg 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* see pulse-notes.txt
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core-error.h>
#include <pulsecore/sink.h>
#include <pulsecore/module.h>
#include <pulsecore/core-util.h>
#include <pulsecore/modargs.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
#include <pulsecore/thread-mq.h>
#include <pulsecore/rtpoll.h>
/* defined in pulse/version.h */
#if PA_PROTOCOL_VERSION > 28
/* these used to be defined in pulsecore/macro.h */
typedef bool pa_bool_t;
#define FALSE ((pa_bool_t) 0)
#define TRUE (!FALSE)
#else
#endif
#include "module-xrdp-sink-symdef.h"
#include "../../../common/xrdp_sockets.h"
PA_MODULE_AUTHOR("Jay Sorg");
PA_MODULE_DESCRIPTION("xrdp sink");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"sink_name=<name for the sink> "
"sink_properties=<properties for the sink> "
"format=<sample format> "
"rate=<sample rate> "
"channels=<number of channels> "
"channel_map=<channel map>");
#define DEFAULT_SINK_NAME "xrdp-sink"
#define BLOCK_USEC 30000
//#define BLOCK_USEC (PA_USEC_PER_SEC * 2)
struct userdata {
pa_core *core;
pa_module *module;
pa_sink *sink;
pa_thread *thread;
pa_thread_mq thread_mq;
pa_rtpoll *rtpoll;
pa_usec_t block_usec;
pa_usec_t timestamp;
pa_usec_t failed_connect_time;
pa_usec_t last_send_time;
int fd; /* unix domain socket connection to xrdp chansrv */
int display_num;
int skip_bytes;
int got_max_latency;
};
static const char* const valid_modargs[] = {
"sink_name",
"sink_properties",
"format",
"rate",
"channels",
"channel_map",
NULL
};
static int close_send(struct userdata *u);
static int sink_process_msg(pa_msgobject *o, int code, void *data,
int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK(o)->userdata;
pa_usec_t now;
long lat;
pa_log_debug("sink_process_msg: code %d", code);
switch (code) {
case PA_SINK_MESSAGE_SET_VOLUME: /* 3 */
break;
case PA_SINK_MESSAGE_SET_MUTE: /* 6 */
break;
case PA_SINK_MESSAGE_GET_LATENCY: /* 7 */
now = pa_rtclock_now();
lat = u->timestamp > now ? u->timestamp - now : 0ULL;
pa_log_debug("sink_process_msg: lat %ld", lat);
*((pa_usec_t*) data) = lat;
return 0;
case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: /* 8 */
break;
case PA_SINK_MESSAGE_SET_STATE: /* 9 */
if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING) /* 0 */ {
pa_log("sink_process_msg: running");
u->timestamp = pa_rtclock_now();
} else {
pa_log("sink_process_msg: not running");
close_send(u);
}
break;
}
return pa_sink_process_msg(o, code, data, offset, chunk);
}
static void sink_update_requested_latency_cb(pa_sink *s) {
struct userdata *u;
size_t nbytes;
pa_sink_assert_ref(s);
pa_assert_se(u = s->userdata);
u->block_usec = BLOCK_USEC;
//u->block_usec = pa_sink_get_requested_latency_within_thread(s);
pa_log("1 block_usec %llu", (unsigned long long) u->block_usec);
u->got_max_latency = 0;
if (u->block_usec == (pa_usec_t) -1) {
u->block_usec = s->thread_info.max_latency;
pa_log_debug("2 block_usec %llu", (unsigned long long) u->block_usec);
u->got_max_latency = 1;
}
nbytes = pa_usec_to_bytes(u->block_usec, &s->sample_spec);
pa_sink_set_max_rewind_within_thread(s, nbytes);
pa_sink_set_max_request_within_thread(s, nbytes);
}
static void process_rewind(struct userdata *u, pa_usec_t now) {
size_t rewind_nbytes, in_buffer;
pa_usec_t delay;
pa_assert(u);
/* Figure out how much we shall rewind and reset the counter */
rewind_nbytes = u->sink->thread_info.rewind_nbytes;
u->sink->thread_info.rewind_nbytes = 0;
pa_assert(rewind_nbytes > 0);
pa_log_debug("Requested to rewind %lu bytes.",
(unsigned long) rewind_nbytes);
if (u->timestamp <= now)
goto do_nothing;
delay = u->timestamp - now;
in_buffer = pa_usec_to_bytes(delay, &u->sink->sample_spec);
if (in_buffer <= 0)
goto do_nothing;
if (rewind_nbytes > in_buffer)
rewind_nbytes = in_buffer;
pa_sink_process_rewind(u->sink, rewind_nbytes);
u->timestamp -= pa_bytes_to_usec(rewind_nbytes, &u->sink->sample_spec);
u->skip_bytes += rewind_nbytes;
pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
return;
do_nothing:
pa_sink_process_rewind(u->sink, 0);
}
struct header {
int code;
int bytes;
};
static int get_display_num_from_display(char *display_text) {
int index;
int mode;
int host_index;
int disp_index;
int scre_index;
int display_num;
char host[256];
char disp[256];
char scre[256];
if (display_text == NULL) {
return 0;
}
memset(host, 0, 256);
memset(disp, 0, 256);
memset(scre, 0, 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;
display_num = atoi(disp);
return display_num;
}
static int lsend(int fd, char *data, int bytes) {
int sent = 0;
int error;
while (sent < bytes) {
error = send(fd, data + sent, bytes - sent, 0);
if (error < 1) {
return error;
}
sent += error;
}
return sent;
}
static int data_send(struct userdata *u, pa_memchunk *chunk) {
char *data;
char *socket_dir;
int bytes;
int sent;
int fd;
struct header h;
struct sockaddr_un s;
if (u->fd == 0) {
if (u->failed_connect_time != 0) {
if (pa_rtclock_now() - u->failed_connect_time < 1000000) {
return 0;
}
}
fd = socket(PF_LOCAL, SOCK_STREAM, 0);
memset(&s, 0, sizeof(s));
s.sun_family = AF_UNIX;
bytes = sizeof(s.sun_path) - 1;
socket_dir = getenv("XRDP_SOCKET_PATH");
if (socket_dir == NULL || socket_dir[0] == '\0')
{
socket_dir = "/tmp/.xrdp";
}
snprintf(s.sun_path, bytes, "%s/" CHANSRV_PORT_OUT_BASE_STR,
socket_dir, u->display_num);
pa_log_debug("trying to connect to %s", s.sun_path);
if (connect(fd, (struct sockaddr *)&s,
sizeof(struct sockaddr_un)) != 0) {
u->failed_connect_time = pa_rtclock_now();
pa_log_debug("Connected failed");
close(fd);
return 0;
}
u->failed_connect_time = 0;
pa_log("Connected ok fd %d", fd);
u->fd = fd;
}
bytes = chunk->length;
pa_log_debug("bytes %d", bytes);
/* from rewind */
if (u->skip_bytes > 0) {
if (bytes > u->skip_bytes) {
bytes -= u->skip_bytes;
u->skip_bytes = 0;
} else {
u->skip_bytes -= bytes;
return bytes;
}
}
h.code = 0;
h.bytes = bytes + 8;
if (lsend(u->fd, (char*)(&h), 8) != 8) {
pa_log("data_send: send failed");
close(u->fd);
u->fd = 0;
return 0;
} else {
pa_log_debug("data_send: sent header ok bytes %d", bytes);
}
data = (char*)pa_memblock_acquire(chunk->memblock);
data += chunk->index;
sent = lsend(u->fd, data, bytes);
pa_memblock_release(chunk->memblock);
if (sent != bytes) {
pa_log("data_send: send failed sent %d bytes %d", sent, bytes);
close(u->fd);
u->fd = 0;
return 0;
}
return sent;
}
static int close_send(struct userdata *u) {
struct header h;
pa_log("close_send:");
if (u->fd == 0) {
return 0;
}
h.code = 1;
h.bytes = 8;
if (lsend(u->fd, (char*)(&h), 8) != 8) {
pa_log("close_send: send failed");
close(u->fd);
u->fd = 0;
return 0;
} else {
pa_log_debug("close_send: sent header ok");
}
return 8;
}
static void process_render(struct userdata *u, pa_usec_t now) {
pa_memchunk chunk;
int request_bytes;
pa_assert(u);
if (u->got_max_latency) {
return;
}
pa_log_debug("process_render: u->block_usec %llu", (unsigned long long) u->block_usec);
while (u->timestamp < now + u->block_usec) {
request_bytes = u->sink->thread_info.max_request;
request_bytes = MIN(request_bytes, 16 * 1024);
pa_sink_render(u->sink, request_bytes, &chunk);
data_send(u, &chunk);
pa_memblock_unref(chunk.memblock);
u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
}
}
static void thread_func(void *userdata) {
struct userdata *u = userdata;
int ret;
pa_usec_t now;
pa_assert(u);
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
u->timestamp = pa_rtclock_now();
for (;;) {
if (u->sink->thread_info.state == PA_SINK_RUNNING) {
now = pa_rtclock_now();
if (u->sink->thread_info.rewind_requested) {
if (u->sink->thread_info.rewind_nbytes > 0) {
process_rewind(u, now);
} else {
pa_sink_process_rewind(u->sink, 0);
}
}
if (u->timestamp <= now) {
pa_log_debug("thread_func: calling process_render");
process_render(u, now);
}
pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
} else {
pa_rtpoll_set_timer_disabled(u->rtpoll);
}
#if defined(PA_CHECK_VERSION) && PA_CHECK_VERSION(6, 0, 0)
if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) {
#else
if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) {
#endif
goto fail;
}
if (ret == 0) {
goto finish;
}
}
fail:
/* If this was no regular exit from the loop we have to continue
* processing messages until we received PA_MESSAGE_SHUTDOWN */
pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core),
PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0,
NULL, NULL);
pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
finish:
pa_log_debug("Thread shutting down");
}
int pa__init(pa_module*m) {
struct userdata *u = NULL;
pa_sample_spec ss;
pa_channel_map map;
pa_modargs *ma = NULL;
pa_sink_new_data data;
size_t nbytes;
pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments.");
goto fail;
}
ss = m->core->default_sample_spec;
map = m->core->default_channel_map;
if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map,
PA_CHANNEL_MAP_DEFAULT) < 0) {
pa_log("Invalid sample format specification or channel map");
goto fail;
}
m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
pa_sink_new_data_init(&data);
data.driver = __FILE__;
data.module = m;
pa_sink_new_data_set_name(&data,
pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "xrdp sink");
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist,
PA_UPDATE_REPLACE) < 0) {
pa_log("Invalid properties");
pa_sink_new_data_done(&data);
goto fail;
}
u->sink = pa_sink_new(m->core, &data,
PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY);
pa_sink_new_data_done(&data);
if (!u->sink) {
pa_log("Failed to create sink object.");
goto fail;
}
u->sink->parent.process_msg = sink_process_msg;
u->sink->update_requested_latency = sink_update_requested_latency_cb;
u->sink->userdata = u;
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
pa_sink_set_rtpoll(u->sink, u->rtpoll);
u->block_usec = BLOCK_USEC;
pa_log_debug("3 block_usec %llu", (unsigned long long) u->block_usec);
nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
pa_sink_set_max_rewind(u->sink, nbytes);
pa_sink_set_max_request(u->sink, nbytes);
u->display_num = get_display_num_from_display(getenv("DISPLAY"));
#if defined(PA_CHECK_VERSION)
#if PA_CHECK_VERSION(0, 9, 22)
if (!(u->thread = pa_thread_new("xrdp-sink", thread_func, u))) {
#else
if (!(u->thread = pa_thread_new(thread_func, u))) {
#endif
#else
if (!(u->thread = pa_thread_new(thread_func, u))) {
#endif
pa_log("Failed to create thread.");
goto fail;
}
pa_sink_put(u->sink);
pa_modargs_free(ma);
return 0;
fail:
if (ma) {
pa_modargs_free(ma);
}
pa__done(m);
return -1;
}
int pa__get_n_used(pa_module *m) {
struct userdata *u;
pa_assert(m);
pa_assert_se(u = m->userdata);
return pa_sink_linked_by(u->sink);
}
void pa__done(pa_module*m) {
struct userdata *u;
pa_assert(m);
if (!(u = m->userdata)) {
return;
}
if (u->sink) {
pa_sink_unlink(u->sink);
}
if (u->thread) {
pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN,
NULL, 0, NULL);
pa_thread_free(u->thread);
}
pa_thread_mq_done(&u->thread_mq);
if (u->sink) {
pa_sink_unref(u->sink);
}
if (u->rtpoll) {
pa_rtpoll_free(u->rtpoll);
}
pa_xfree(u);
}

View File

@ -1,29 +0,0 @@
#ifndef MODULE_XRDP_SOURCE_SYMDEF_H
#define MODULE_XRDP_SOURCE_SYMDEF_H
#include <pulsecore/core.h>
#include <pulsecore/module.h>
#include <pulsecore/macro.h>
#define pa__init module_xrdp_source_LTX_pa__init
#define pa__done module_xrdp_source_LTX_pa__done
#define pa__get_author module_xrdp_source_LTX_pa__get_author
#define pa__get_description module_xrdp_source_LTX_pa__get_description
#define pa__get_usage module_xrdp_source_LTX_pa__get_usage
#define pa__get_version module_xrdp_source_LTX_pa__get_version
#define pa__get_deprecated module_xrdp_source_LTX_pa__get_deprecated
#define pa__load_once module_xrdp_source_LTX_pa__load_once
#define pa__get_n_used module_xrdp_source_LTX_pa__get_n_used
int pa__init(pa_module*m);
void pa__done(pa_module*m);
int pa__get_n_used(pa_module*m);
const char* pa__get_author(void);
const char* pa__get_description(void);
const char* pa__get_usage(void);
const char* pa__get_version(void);
const char* pa__get_deprecated(void);
pa_bool_t pa__load_once(void);
#endif

View File

@ -1,547 +0,0 @@
/***
This file is part of PulseAudio.
Copyright 2004-2008 Lennart Poettering
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
PulseAudio 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 Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/modargs.h>
#include <pulsecore/module.h>
#include <pulsecore/rtpoll.h>
#include <pulsecore/source.h>
#include <pulsecore/thread-mq.h>
#include <pulsecore/thread.h>
/* defined in pulse/version.h */
#if PA_PROTOCOL_VERSION > 28
/* these used to be defined in pulsecore/macro.h */
typedef bool pa_bool_t;
#define FALSE ((pa_bool_t) 0)
#define TRUE (!FALSE)
#else
#endif
#include "module-xrdp-source-symdef.h"
#include "../../../common/xrdp_sockets.h"
PA_MODULE_AUTHOR("Laxmikant Rashinkar");
PA_MODULE_DESCRIPTION("xrdp source");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"format=<sample format> "
"channels=<number of channels> "
"rate=<sample rate> "
"source_name=<name of source> "
"channel_map=<channel map> "
"description=<description for the source> "
"latency_time=<latency time in ms>");
#define DEFAULT_SOURCE_NAME "xrdp-source"
#define DEFAULT_LATENCY_TIME 10
#define MAX_LATENCY_USEC 1000
struct userdata {
pa_core *core;
pa_module *module;
pa_source *source;
pa_thread *thread;
pa_thread_mq thread_mq;
pa_rtpoll *rtpoll;
size_t block_size;
pa_usec_t block_usec;
pa_usec_t timestamp;
pa_usec_t latency_time;
/* xrdp stuff */
int fd; /* UDS connection to xrdp chansrv */
int display_num; /* X display number */
int want_src_data;
};
static const char* const valid_modargs[] = {
"rate",
"format",
"channels",
"source_name",
"channel_map",
"description",
"latency_time",
NULL
};
static int get_display_num_from_display(char *display_text) ;
static int source_process_msg(pa_msgobject *o, int code, void *data,
int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SOURCE(o)->userdata;
switch (code) {
case PA_SOURCE_MESSAGE_SET_STATE:
if (PA_PTR_TO_UINT(data) == PA_SOURCE_RUNNING)
u->timestamp = pa_rtclock_now();
break;
case PA_SOURCE_MESSAGE_GET_LATENCY: {
pa_usec_t now;
now = pa_rtclock_now();
*((pa_usec_t*) data) = u->timestamp > now ? u->timestamp - now : 0;
return 0;
}
}
return pa_source_process_msg(o, code, data, offset, chunk);
}
static void source_update_requested_latency_cb(pa_source *s) {
struct userdata *u;
pa_source_assert_ref(s);
u = s->userdata;
pa_assert(u);
u->block_usec = pa_source_get_requested_latency_within_thread(s);
}
static int lsend(int fd, char *data, int bytes) {
int sent = 0;
int error;
while (sent < bytes) {
error = send(fd, data + sent, bytes - sent, 0);
if (error < 1) {
return error;
}
sent += error;
}
return sent;
}
static int lrecv(int fd, char *data, int bytes) {
int recved = 0;
int error;
while (recved < bytes) {
error = recv(fd, data + recved, bytes - recved, 0);
if (error < 1) {
return error;
}
recved += error;
}
return recved;
}
static int data_get(struct userdata *u, pa_memchunk *chunk) {
int fd;
int bytes;
int read_bytes;
struct sockaddr_un s;
char *data;
char *socket_dir;
char buf[11];
unsigned char ubuf[10];
if (u->fd == 0) {
/* connect to xrdp unix domain socket */
fd = socket(PF_LOCAL, SOCK_STREAM, 0);
memset(&s, 0, sizeof(s));
s.sun_family = AF_UNIX;
bytes = sizeof(s.sun_path) - 1;
socket_dir = getenv("XRDP_SOCKET_PATH");
if (socket_dir == NULL || socket_dir[0] == '\0')
{
socket_dir = "/tmp/.xrdp";
}
snprintf(s.sun_path, bytes, "%s/" CHANSRV_PORT_IN_BASE_STR,
socket_dir, u->display_num);
pa_log_debug("Trying to connect to %s", s.sun_path);
if (connect(fd, (struct sockaddr *) &s, sizeof(struct sockaddr_un)) != 0) {
pa_log_debug("Connect failed");
close(fd);
return -1;
}
pa_log("Connected ok, fd=%d", fd);
pa_log_debug("###### connected to xrdp audio_in socket");
u->fd = fd;
}
data = (char *) pa_memblock_acquire(chunk->memblock);
if (!u->want_src_data) {
char buf[12];
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
buf[3] = 0;
buf[4] = 11;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 1;
buf[9] = 0;
buf[10] = 0;
if (lsend(u->fd, buf, 11) != 11) {
close(u->fd);
u->fd = 0;
pa_memblock_release(chunk->memblock);
return -1;
}
u->want_src_data = 1;
pa_log_debug("###### started recording");
}
/* ask for more data */
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
buf[3] = 0;
buf[4] = 11;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 3;
buf[9] = (unsigned char) chunk->length;
buf[10] = (unsigned char) ((chunk->length >> 8) & 0xff);
if (lsend(u->fd, buf, 11) != 11) {
close(u->fd);
u->fd = 0;
pa_memblock_release(chunk->memblock);
u->want_src_data = 0;
return -1;
}
/* read length of data available */
if (lrecv(u->fd, (char *) ubuf, 2) != 2) {
close(u->fd);
u->fd = 0;
pa_memblock_release(chunk->memblock);
u->want_src_data = 0;
return -1;
}
bytes = ((ubuf[1] << 8) & 0xff00) | (ubuf[0] & 0xff);
if (bytes == 0) {
pa_memblock_release(chunk->memblock);
return 0;
}
/* get data */
read_bytes = lrecv(u->fd, data, bytes);
if (read_bytes != bytes) {
close(u->fd);
u->fd = 0;
pa_memblock_release(chunk->memblock);
u->want_src_data = 0;
return -1;
}
pa_memblock_release(chunk->memblock);
return read_bytes;
}
static void thread_func(void *userdata) {
struct userdata *u = userdata;
int bytes;
pa_assert(u);
pa_thread_mq_install(&u->thread_mq);
u->timestamp = pa_rtclock_now();
for (;;) {
int ret;
/* Generate some null data */
if (u->source->thread_info.state == PA_SOURCE_RUNNING) {
pa_usec_t now;
pa_memchunk chunk;
now = pa_rtclock_now();
if ((chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec)) > 0) {
chunk.length *= 4;
chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length);
chunk.index = 0;
bytes = data_get(u, &chunk);
if (bytes > 0)
{
chunk.length = bytes;
pa_source_post(u->source, &chunk);
}
pa_memblock_unref(chunk.memblock);
u->timestamp = now;
}
pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->latency_time * PA_USEC_PER_MSEC);
} else {
if (u->want_src_data)
{
/* we don't want source data anymore */
char buf[12];
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
buf[3] = 0;
buf[4] = 11;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 2;
buf[9] = 0;
buf[10] = 0;
if (lsend(u->fd, buf, 11) != 11) {
close(u->fd);
u->fd = 0;
}
u->want_src_data = 0;
pa_log_debug("###### stopped recording");
}
pa_rtpoll_set_timer_disabled(u->rtpoll);
}
/* Hmm, nothing to do. Let's sleep */
#if defined(PA_CHECK_VERSION) && PA_CHECK_VERSION(6, 0, 0)
if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) {
#else
if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) {
#endif
goto fail;
}
if (ret == 0)
goto finish;
}
fail:
/* If this was no regular exit from the loop we have to continue
* processing messages until we received PA_MESSAGE_SHUTDOWN */
pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
finish:
pa_log_debug("###### thread shutting down");
}
int pa__init(pa_module *m) {
struct userdata *u = NULL;
pa_sample_spec ss;
pa_channel_map map;
pa_modargs *ma = NULL;
pa_source_new_data data;
uint32_t latency_time = DEFAULT_LATENCY_TIME;
pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments.");
goto fail;
}
#if 1
ss = m->core->default_sample_spec;
#else
ss.format = PA_SAMPLE_S16LE;
ss.rate = 22050;
ss.channels = 2;
#endif
map = m->core->default_channel_map;
if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
pa_log("Invalid sample format specification or channel map");
goto fail;
}
m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
pa_source_new_data_init(&data);
data.driver = __FILE__;
data.module = m;
pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
pa_source_new_data_set_sample_spec(&data, &ss);
pa_source_new_data_set_channel_map(&data, &map);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "xrdp source"));
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY);
pa_source_new_data_done(&data);
if (!u->source) {
pa_log("Failed to create source object.");
goto fail;
}
u->latency_time = DEFAULT_LATENCY_TIME;
if (pa_modargs_get_value_u32(ma, "latency_time", &latency_time) < 0) {
pa_log("Failed to parse latency_time value.");
goto fail;
}
u->latency_time = latency_time;
u->source->parent.process_msg = source_process_msg;
u->source->update_requested_latency = source_update_requested_latency_cb;
u->source->userdata = u;
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
pa_source_set_rtpoll(u->source, u->rtpoll);
pa_source_set_latency_range(u->source, 0, MAX_LATENCY_USEC);
u->block_usec = u->source->thread_info.max_latency;
u->source->thread_info.max_rewind =
pa_usec_to_bytes(u->block_usec, &u->source->sample_spec);
#if defined(PA_CHECK_VERSION)
#if PA_CHECK_VERSION(0, 9, 22)
if (!(u->thread = pa_thread_new("xrdp-source", thread_func, u))) {
#else
if (!(u->thread = pa_thread_new(thread_func, u))) {
#endif
#else
if (!(u->thread = pa_thread_new(thread_func, u)))
#endif
pa_log("Failed to create thread.");
goto fail;
}
pa_source_put(u->source);
pa_modargs_free(ma);
u->display_num = get_display_num_from_display(getenv("DISPLAY"));
return 0;
fail:
if (ma)
pa_modargs_free(ma);
pa__done(m);
return -1;
}
void pa__done(pa_module*m) {
struct userdata *u;
pa_assert(m);
if (!(u = m->userdata))
return;
if (u->source)
pa_source_unlink(u->source);
if (u->thread) {
pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
pa_thread_free(u->thread);
}
pa_thread_mq_done(&u->thread_mq);
if (u->source)
pa_source_unref(u->source);
if (u->rtpoll)
pa_rtpoll_free(u->rtpoll);
pa_xfree(u);
}
static int get_display_num_from_display(char *display_text) {
int index;
int mode;
int host_index;
int disp_index;
int scre_index;
int display_num;
char host[256];
char disp[256];
char scre[256];
if (display_text == NULL) {
return 0;
}
memset(host, 0, 256);
memset(disp, 0, 256);
memset(scre, 0, 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;
display_num = atoi(disp);
return display_num;
}

View File

@ -28,6 +28,7 @@
#include "log.h"
#include "clipboard.h"
#include "rail.h"
#include "xcommon.h"
/*
#undef LOG_LEVEL
@ -50,6 +51,9 @@ Atom g_utf8_string = 0;
Atom g_net_wm_name = 0;
Atom g_wm_state = 0;
static x_server_fatal_cb_type x_server_fatal_handler = 0;
/*****************************************************************************/
static int
xcommon_error_handler(Display *dis, XErrorEvent *xer)
@ -64,16 +68,27 @@ xcommon_error_handler(Display *dis, XErrorEvent *xer)
}
/*****************************************************************************/
/* The X server had an internal error. This is the last function called.
Do any cleanup that needs to be done on exit, like removing temporary files.
/* Allow the caller to be notified on X server failure
Specified callback can do any cleanup that needs to be done on exit,
like removing temporary files. This is the last function called.
Don't worry about memory leaks */
#if 0
void
xcommon_set_x_server_fatal_handler(x_server_fatal_cb_type handler)
{
x_server_fatal_handler = handler;
}
/*****************************************************************************/
/* The X server had an internal error */
static int
xcommon_fatal_handler(Display *dis)
{
if (x_server_fatal_handler)
{
x_server_fatal_handler();
}
return 0;
}
#endif
/*****************************************************************************/
/* returns time in milliseconds
@ -110,7 +125,7 @@ xcommon_init(void)
/* setting the error handlers can cause problem when shutting down
chansrv on some xlibs */
XSetErrorHandler(xcommon_error_handler);
//XSetIOErrorHandler(xcommon_fatal_handler);
XSetIOErrorHandler(xcommon_fatal_handler);
g_x_socket = XConnectionNumber(g_display);

View File

@ -26,6 +26,8 @@
#define FORMAT_TO_BYTES(_format) \
(_format) == 32 ? sizeof(long) : (_format) / 8
typedef void (*x_server_fatal_cb_type)(void);
int
xcommon_get_local_time(void);
int
@ -34,5 +36,7 @@ int
xcommon_get_wait_objs(tbus* objs, int* count, int* timeout);
int
xcommon_check_wait_objs(void);
void
xcommon_set_x_server_fatal_handler(x_server_fatal_cb_type handler);
#endif

View File

@ -30,6 +30,7 @@
#include <grp.h>
#include "xrdp_sockets.h"
#include "list.h"
#include "sesman.h"
#include "ssl_calls.h"
@ -143,6 +144,12 @@ env_set_user(const char *username, char **passwd_file, int display,
g_setenv("XRDP_SESSION", "1", 1);
/* XRDP_SOCKET_PATH should be set even here, chansrv uses this */
g_setenv("XRDP_SOCKET_PATH", XRDP_SOCKET_PATH, 1);
/* pulse sink socket */
g_snprintf(text, sizeof(text) - 1, CHANSRV_PORT_OUT_BASE_STR, display);
g_setenv("XRDP_PULSE_SINK_SOCKET", text, 1);
/* pulse source socket */
g_snprintf(text, sizeof(text) - 1, CHANSRV_PORT_IN_BASE_STR, display);
g_setenv("XRDP_PULSE_SOURCE_SOCKET", text, 1);
if ((env_names != 0) && (env_values != 0) &&
(env_names->count == env_values->count))
{

View File

@ -26,6 +26,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include "xrdp_sockets.h"
@ -76,6 +77,10 @@ int main(int argc, char **argv)
{
printf("message sent ok\n");
}
else
{
printf("message send failed: %s\n", strerror(errno));
}
return 0;
}

View File

@ -28,8 +28,8 @@ crypt_level=high
certificate=
key_file=
; set SSL protocols
; can be comma separated list of 'SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2'
ssl_protocols=TLSv1, TLSv1.1, TLSv1.2
; can be comma separated list of 'SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'
ssl_protocols=TLSv1.2, TLSv1.3
; set TLS cipher suites
#tls_ciphers=HIGH
@ -96,7 +96,7 @@ ls_logo_y_pos=50
; for positioning labels such as username, password etc
ls_label_x_pos=30
ls_label_width=60
ls_label_width=65
; for positioning text and combo boxes next to above labels
ls_input_x_pos=110

View File

@ -386,7 +386,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
else if (g_strncmp(ASK, value, ASK_LEN) == 0)
{
/* label */
b = xrdp_bitmap_create(95, DEFAULT_EDIT_H, self->screen->bpp,
b = xrdp_bitmap_create(globals->ls_label_width, DEFAULT_EDIT_H, self->screen->bpp,
WND_TYPE_LABEL, self);
list_insert_item(self->login_window->child_list, insert_index,
(long)b);
@ -401,7 +401,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
set_string(&b->caption1, name);
/* edit */
b = xrdp_bitmap_create(DEFAULT_EDIT_W, DEFAULT_EDIT_H, self->screen->bpp,
b = xrdp_bitmap_create(globals->ls_input_width, DEFAULT_EDIT_H, self->screen->bpp,
WND_TYPE_EDIT, self);
list_insert_item(self->login_window->child_list, insert_index,
(long)b);
@ -859,7 +859,7 @@ load_xrdp_config(struct xrdp_config *config, int bpp)
globals->ls_logo_x_pos = 63;
globals->ls_logo_y_pos = 50;
globals->ls_label_x_pos = 30;
globals->ls_label_width = 60;
globals->ls_label_width = 65;
globals->ls_input_x_pos = 110;
globals->ls_input_width = 210;
globals->ls_input_y_pos = 150;

View File

@ -496,9 +496,7 @@ struct xrdp_bitmap
#define DEFAULT_ELEMENT_TOP 35
#define DEFAULT_BUTTON_W 60
#define DEFAULT_BUTTON_H 23
#define DEFAULT_COMBO_W 210
#define DEFAULT_COMBO_H 21
#define DEFAULT_EDIT_W 210
#define DEFAULT_EDIT_H 21
#define DEFAULT_WND_LOGIN_W 425
#define DEFAULT_WND_LOGIN_H 475