a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* -*- c-basic-offset: 8 -*-
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop: A Remote Desktop Protocol client.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Master/Slave remote controlling
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright 2013 Henrik Andersson <hean01@cendio.se> for Cendio AB
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is free software: you can redistribute it and/or modify
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it under the terms of the GNU General Public License as published by
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the Free Software Foundation, either version 3 of the License, or
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (at your option) any later version.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is distributed in the hope that it will be useful,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync but WITHOUT ANY WARRANTY; without even the implied warranty of
a180a41bba1d50822df23fff0099e90b86638b89vboxsync MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a180a41bba1d50822df23fff0099e90b86638b89vboxsync GNU General Public License for more details.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync You should have received a copy of the GNU General Public License
a180a41bba1d50822df23fff0099e90b86638b89vboxsync along with this program. If not, see <http://www.gnu.org/licenses/>.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync*/
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/*
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * the General Public License version 2 (GPLv2) at this time for any software where
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * a choice of GPL license versions is made available with the language indicating
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * that GPLv2 or any later version may be used, or where a choice of which version
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * of the GPL is applied is otherwise unspecified.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include "rdesktop.h"
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include "ssl.h"
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <stdio.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <stdlib.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <sys/types.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <sys/socket.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <sys/stat.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <sys/un.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <limits.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <unistd.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define CTRL_LINEBUF_SIZE 1024
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define CTRL_RESULT_SIZE 32
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define RDESKTOP_CTRLSOCK_STORE "/.local/share/rdesktop/ctrl"
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define CTRL_HASH_FLAG_SEAMLESS 1
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define ERR_RESULT_OK 0x00
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define ERR_RESULT_NO_SUCH_COMMAND 0xffffffff
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern RD_BOOL g_seamless_rdp;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern uint8 g_static_rdesktop_salt_16[];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL _ctrl_is_slave;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic int ctrlsock;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic char ctrlsock_name[PATH_MAX];
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic struct _ctrl_slave_t *_ctrl_slaves;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define CMD_SEAMLESS_SPAWN "seamless.spawn"
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsynctypedef struct _ctrl_slave_t
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct _ctrl_slave_t *prev, *next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int sock;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char linebuf[CTRL_LINEBUF_SIZE];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync} _ctrl_slave_t;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_ctrl_slave_new(int sock)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_t *it, *ns;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* initialize new slave list item */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(ns, 0, sizeof(_ctrl_slave_t));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ns->sock = sock;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* append new slave to end of list */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = _ctrl_slaves;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* find last element in list */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (it && it->next)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = it->next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* if last found append new */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it->next = ns;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ns->prev = it;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* no elemnts in list, lets add first */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slaves = ns;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_ctrl_slave_disconnect(int sock)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_t *it;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!_ctrl_slaves)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = _ctrl_slaves;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* find slave with sock */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (it->next && it->sock != sock)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = it->next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it->sock == sock)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* shutdown socket */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync shutdown(sock, SHUT_RDWR);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync close(sock);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* remove item from list */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it == _ctrl_slaves)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it->next)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slaves = it->next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slaves = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it->prev)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (it->prev)->next = it->next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it->next)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (it->next)->prev = it->prev;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (it->next)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (it->next)->prev = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(it);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_ctrl_command_result(_ctrl_slave_t * slave, int result)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char buf[64] = { 0 };
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* translate and send result code back to client */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (result == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync send(slave->sock, "OK\n", 3, 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync snprintf(buf, 64, "ERROR %x\n", result);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync send(slave->sock, buf, strlen(buf), 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_ctrl_dispatch_command(_ctrl_slave_t * slave)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *p;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *cmd;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned int res;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* unescape linebuffer */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cmd = utils_string_unescape(slave->linebuf);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* process seamless spawn request */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync p = strstr(cmd, "seamlessrdpshell.exe");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (p)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync p += strlen("seamlessrdpshell.exe") + 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = ERR_RESULT_OK;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (seamless_send_spawn(p) == (unsigned int) -1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = ERR_RESULT_NO_SUCH_COMMAND;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(cmd);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_command_result(slave, res);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_ctrl_verify_unix_socket()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int s, len;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct sockaddr_un saun;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(&saun, 0, sizeof(struct sockaddr_un));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("Error creating ctrl client socket: socket()");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync saun.sun_family = AF_UNIX;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync strcpy(saun.sun_path, ctrlsock_name);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync len = sizeof(saun.sun_family) + strlen(saun.sun_path);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* test connection */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (connect(s, (struct sockaddr *) &saun, len) != 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync shutdown(s, SHUT_RDWR);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync close(s);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync RDSSL_SHA1 sha1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 out[20], delim;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 version;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint32 flags;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* version\0user\0domain\0host\0flags */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync flags = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync delim = '\0';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync version = 0x0100;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_seamless_rdp)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync flags = CTRL_HASH_FLAG_SEAMLESS;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_init(&sha1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, (uint8 *) & version, sizeof(version));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, &delim, 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (user)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, (uint8 *) user, strlen(user));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, &delim, 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (domain)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, (uint8 *) domain, strlen(domain));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, &delim, 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (host)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, (uint8 *) host, strlen(host));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, &delim, 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_update(&sha1, (uint8 *) & flags, sizeof(flags));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdssl_sha1_final(&sha1, out);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync sec_hash_to_string(hash, hsize, out, sizeof(out));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/** Initialize ctrl
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Ret values: <0 failure, 0 master, 1 client
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncint
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncctrl_init(const char *user, const char *domain, const char *host)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct stat st;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct sockaddr_un saun;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char hash[41], path[PATH_MAX];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *home;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* check if ctrl already initialized */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (ctrlsock != 0 || _ctrl_is_slave)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync home = getenv("HOME");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (home == NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return -1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* get uniq hash for ctrlsock name */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_create_hash(user, domain, host, hash, 41);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync snprintf(ctrlsock_name, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ctrlsock_name[sizeof(ctrlsock_name) - 1] = '\0';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* make sure that ctrlsock store path exists */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync snprintf(path, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE, home);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync path[sizeof(path) - 1] = '\0';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (utils_mkdir_p(path, 0700) == -1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror(path);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return -1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* check if ctrl socket already exist then this process becomes a client */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (stat(ctrlsock_name, &st) == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* verify that unix socket is not stale */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (_ctrl_verify_unix_socket() == True)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_is_slave = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unlink(ctrlsock_name);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* setup ctrl socket and start listening for connections */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("Error creating ctrl socket:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* bind and start listening on server socket */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(&saun, 0, sizeof(struct sockaddr_un));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync saun.sun_family = AF_UNIX;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("Error binding ctrl socket:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (listen(ctrlsock, 5) < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("Error listening on socket:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* add ctrl cleanup func to exit hooks */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync atexit(ctrl_cleanup);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncctrl_cleanup()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (ctrlsock)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync close(ctrlsock);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unlink(ctrlsock_name);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncRD_BOOL
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncctrl_is_slave()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return _ctrl_is_slave;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncctrl_add_fds(int *n, fd_set * rfds)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_t *it;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (ctrlsock == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync FD_SET(ctrlsock, rfds);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *n = MAX(*n, ctrlsock);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* add connected slaves to fd set */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = _ctrl_slaves;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (it)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync FD_SET(it->sock, rfds);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *n = MAX(*n, it->sock);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = it->next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncctrl_check_fds(fd_set * rfds, fd_set * wfds)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int ns, res, offs;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct sockaddr_un fsaun;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync socklen_t fromlen;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_t *it;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (ctrlsock == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(&fsaun, 0, sizeof(struct sockaddr_un));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* check if we got any connections on server socket */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (FD_ISSET(ctrlsock, rfds))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync FD_CLR(ctrlsock, rfds);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync fromlen = sizeof(fsaun);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (ns < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("server: accept()");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_new(ns);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* check if any of our slaves fds has data */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = _ctrl_slaves;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (it)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (FD_ISSET(it->sock, rfds))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync offs = strlen(it->linebuf);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync FD_CLR(it->sock, rfds);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* linebuffer full let's disconnect slave */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_disconnect(it->sock);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync break;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (res > 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Check if we got full command line */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *p;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((p = strchr(it->linebuf, '\n')) == NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync continue;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* iterate over string and check against escaped \n */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (p)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Check if newline is escaped */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (p > it->linebuf && *(p - 1) != '\\')
a180a41bba1d50822df23fff0099e90b86638b89vboxsync break;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync p = strchr(p + 1, '\n');
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* If we havent found an nonescaped \n we need more data */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (p == NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync continue;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* strip new linebuf and dispatch command */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *p = '\0';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_dispatch_command(it);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Peer disconnected or socket error */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync _ctrl_slave_disconnect(it->sock);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync break;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it = it->next;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#if HAVE_ICONV
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern char g_codepage[16];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncint
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncctrl_send_command(const char *cmd, const char *arg)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync FILE *fp;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct sockaddr_un saun;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int s, len, index, ret;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char result[CTRL_RESULT_SIZE], c, *escaped;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync escaped = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!_ctrl_is_slave)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return -1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("Error creating ctrl client socket: socket()");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(&saun, 0, sizeof(struct sockaddr_un));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync saun.sun_family = AF_UNIX;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync strcpy(saun.sun_path, ctrlsock_name);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync len = sizeof(saun.sun_family) + strlen(saun.sun_path);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (connect(s, (struct sockaddr *) &saun, len) < 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync perror("Error connecting to ctrl socket: connect()");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync exit(1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Bundle cmd and argument into string, convert to UTF-8 if needed */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync snprintf(data, CTRL_LINEBUF_SIZE, "%s %s", cmd, arg);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ret = utils_locale_to_utf8(data, strlen(data), tmp, CTRL_LINEBUF_SIZE - 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (ret != 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto bail_out;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* escape the utf-8 string */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync escaped = utils_string_escape(tmp);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto bail_out;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* send escaped utf-8 command to master */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync send(s, escaped, strlen(escaped), 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync send(s, "\n", 1, 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* read result from master */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync fp = fdopen(s, "r");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync index = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync result[index] = c;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync index++;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync result[index - 1] = '\0';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (strncmp(result, "ERROR ", 6) == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (sscanf(result, "ERROR %d", &ret) != 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync ret = -1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync bail_out:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(escaped);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync shutdown(s, SHUT_RDWR);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync close(s);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return ret;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}