|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
Packit |
1fb8d4 |
* SSH Agent Virtual Channel Extension
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Copyright 2013 Christian Hofstaedtler
|
|
Packit |
1fb8d4 |
* Copyright 2015 Thincast Technologies GmbH
|
|
Packit |
1fb8d4 |
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
|
Packit |
1fb8d4 |
* Copyright 2017 Ben Cohen
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
1fb8d4 |
* you may not use this file except in compliance with the License.
|
|
Packit |
1fb8d4 |
* You may obtain a copy of the License at
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
1fb8d4 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
1fb8d4 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
1fb8d4 |
* See the License for the specific language governing permissions and
|
|
Packit |
1fb8d4 |
* limitations under the License.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/*
|
|
Packit |
1fb8d4 |
* sshagent_main.c: DVC plugin to forward queries from RDP to the ssh-agent
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* This relays data to and from an ssh-agent program equivalent running on the
|
|
Packit |
1fb8d4 |
* RDP server to an ssh-agent running locally. Unlike the normal ssh-agent,
|
|
Packit |
1fb8d4 |
* which sends data over an SSH channel, the data is send over an RDP dynamic
|
|
Packit |
1fb8d4 |
* virtual channel.
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* protocol specification:
|
|
Packit |
1fb8d4 |
* Forward data verbatim over RDP dynamic virtual channel named "sshagent"
|
|
Packit |
1fb8d4 |
* between a ssh client on the xrdp server and the real ssh-agent where
|
|
Packit |
1fb8d4 |
* the RDP client is running. Each connection by a separate client to
|
|
Packit |
1fb8d4 |
* xrdp-ssh-agent gets a separate DVC invocation.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
1fb8d4 |
#include "config.h"
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <stdio.h>
|
|
Packit |
1fb8d4 |
#include <stdlib.h>
|
|
Packit |
1fb8d4 |
#include <sys/types.h>
|
|
Packit |
1fb8d4 |
#include <sys/socket.h>
|
|
Packit |
1fb8d4 |
#include <sys/un.h>
|
|
Packit |
1fb8d4 |
#include <pwd.h>
|
|
Packit |
1fb8d4 |
#include <unistd.h>
|
|
Packit |
1fb8d4 |
#include <errno.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <winpr/crt.h>
|
|
Packit |
1fb8d4 |
#include <winpr/synch.h>
|
|
Packit |
1fb8d4 |
#include <winpr/thread.h>
|
|
Packit |
1fb8d4 |
#include <winpr/stream.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "sshagent_main.h"
|
|
Packit |
1fb8d4 |
#include <freerdp/channels/log.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#define TAG CHANNELS_TAG("sshagent.client")
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
typedef struct _SSHAGENT_LISTENER_CALLBACK SSHAGENT_LISTENER_CALLBACK;
|
|
Packit |
1fb8d4 |
struct _SSHAGENT_LISTENER_CALLBACK
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
IWTSListenerCallback iface;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
IWTSPlugin* plugin;
|
|
Packit |
1fb8d4 |
IWTSVirtualChannelManager* channel_mgr;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
rdpContext* rdpcontext;
|
|
Packit |
1fb8d4 |
const char* agent_uds_path;
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
typedef struct _SSHAGENT_CHANNEL_CALLBACK SSHAGENT_CHANNEL_CALLBACK;
|
|
Packit |
1fb8d4 |
struct _SSHAGENT_CHANNEL_CALLBACK
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
IWTSVirtualChannelCallback iface;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
IWTSPlugin* plugin;
|
|
Packit |
1fb8d4 |
IWTSVirtualChannelManager* channel_mgr;
|
|
Packit |
1fb8d4 |
IWTSVirtualChannel* channel;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
rdpContext* rdpcontext;
|
|
Packit |
1fb8d4 |
int agent_fd;
|
|
Packit |
1fb8d4 |
HANDLE thread;
|
|
Packit |
1fb8d4 |
CRITICAL_SECTION lock;
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
typedef struct _SSHAGENT_PLUGIN SSHAGENT_PLUGIN;
|
|
Packit |
1fb8d4 |
struct _SSHAGENT_PLUGIN
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
IWTSPlugin iface;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
SSHAGENT_LISTENER_CALLBACK* listener_callback;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
rdpContext* rdpcontext;
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Function to open the connection to the sshagent
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return The fd on success, otherwise -1
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static int connect_to_sshagent(const char* udspath)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int agent_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (agent_fd == -1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Can't open Unix domain socket!");
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
struct sockaddr_un addr;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
memset(&addr, 0, sizeof(addr));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
addr.sun_family = AF_UNIX;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
strncpy(addr.sun_path, udspath, sizeof(addr.sun_path) - 1);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
int rc = connect(agent_fd, (struct sockaddr*)&addr, sizeof(addr));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (rc != 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Can't connect to Unix domain socket \"%s\"!",
|
|
Packit |
1fb8d4 |
udspath);
|
|
Packit |
1fb8d4 |
close(agent_fd);
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return agent_fd;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Entry point for thread to read from the ssh-agent socket and forward
|
|
Packit |
1fb8d4 |
* the data to RDP
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return NULL
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static DWORD WINAPI sshagent_read_thread(LPVOID data)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*)data;
|
|
Packit |
1fb8d4 |
BYTE buffer[4096];
|
|
Packit |
1fb8d4 |
int going = 1;
|
|
Packit |
1fb8d4 |
UINT status = CHANNEL_RC_OK;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (going)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int bytes_read = read(callback->agent_fd,
|
|
Packit |
1fb8d4 |
buffer,
|
|
Packit |
1fb8d4 |
sizeof(buffer));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (bytes_read == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Socket closed cleanly at other end */
|
|
Packit |
1fb8d4 |
going = 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else if (bytes_read < 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (errno != EINTR)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG,
|
|
Packit |
1fb8d4 |
"Error reading from sshagent, errno=%d",
|
|
Packit |
1fb8d4 |
errno);
|
|
Packit |
1fb8d4 |
status = ERROR_READ_FAULT;
|
|
Packit |
1fb8d4 |
going = 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Something read: forward to virtual channel */
|
|
Packit |
1fb8d4 |
status = callback->channel->Write(callback->channel,
|
|
Packit |
1fb8d4 |
bytes_read,
|
|
Packit |
1fb8d4 |
buffer,
|
|
Packit |
1fb8d4 |
NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (status != CHANNEL_RC_OK)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
going = 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
close(callback->agent_fd);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (status != CHANNEL_RC_OK)
|
|
Packit |
1fb8d4 |
setChannelError(callback->rdpcontext, status,
|
|
Packit |
1fb8d4 |
"sshagent_read_thread reported an error");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
ExitThread(status);
|
|
Packit |
1fb8d4 |
return status;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Callback for data received from the RDP server; forward this to ssh-agent
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static UINT sshagent_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*) pChannelCallback;
|
|
Packit |
1fb8d4 |
BYTE* pBuffer = Stream_Pointer(data);
|
|
Packit |
1fb8d4 |
UINT32 cbSize = Stream_GetRemainingLength(data);
|
|
Packit |
1fb8d4 |
BYTE* pos = pBuffer;
|
|
Packit |
1fb8d4 |
/* Forward what we have received to the ssh agent */
|
|
Packit |
1fb8d4 |
UINT32 bytes_to_write = cbSize;
|
|
Packit |
1fb8d4 |
errno = 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (bytes_to_write > 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int bytes_written = write(callback->agent_fd, pos,
|
|
Packit |
1fb8d4 |
bytes_to_write);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (bytes_written < 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (errno != EINTR)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG,
|
|
Packit |
1fb8d4 |
"Error writing to sshagent, errno=%d",
|
|
Packit |
1fb8d4 |
errno);
|
|
Packit |
1fb8d4 |
return ERROR_WRITE_FAULT;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
bytes_to_write -= bytes_written;
|
|
Packit |
1fb8d4 |
pos += bytes_written;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Consume stream */
|
|
Packit |
1fb8d4 |
Stream_Seek(data, cbSize);
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Callback for when the virtual channel is closed
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static UINT sshagent_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*) pChannelCallback;
|
|
Packit |
1fb8d4 |
/* Call shutdown() to wake up the read() in sshagent_read_thread(). */
|
|
Packit |
1fb8d4 |
shutdown(callback->agent_fd, SHUT_RDWR);
|
|
Packit |
1fb8d4 |
EnterCriticalSection(&callback->lock);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (WaitForSingleObject(callback->thread, INFINITE) == WAIT_FAILED)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT error = GetLastError();
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error);
|
|
Packit |
1fb8d4 |
return error;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
CloseHandle(callback->thread);
|
|
Packit |
1fb8d4 |
LeaveCriticalSection(&callback->lock);
|
|
Packit |
1fb8d4 |
DeleteCriticalSection(&callback->lock);
|
|
Packit |
1fb8d4 |
free(callback);
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Callback for when a new virtual channel is opened
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
Packit |
1fb8d4 |
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
|
|
Packit |
1fb8d4 |
IWTSVirtualChannelCallback** ppCallback)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSHAGENT_CHANNEL_CALLBACK* callback;
|
|
Packit |
1fb8d4 |
SSHAGENT_LISTENER_CALLBACK* listener_callback = (SSHAGENT_LISTENER_CALLBACK*) pListenerCallback;
|
|
Packit |
1fb8d4 |
callback = (SSHAGENT_CHANNEL_CALLBACK*) calloc(1, sizeof(SSHAGENT_CHANNEL_CALLBACK));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!callback)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "calloc failed!");
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_NO_MEMORY;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Now open a connection to the local ssh-agent. Do this for each
|
|
Packit |
1fb8d4 |
* connection to the plugin in case we mess up the agent session. */
|
|
Packit |
1fb8d4 |
callback->agent_fd
|
|
Packit |
1fb8d4 |
= connect_to_sshagent(listener_callback->agent_uds_path);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (callback->agent_fd == -1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(callback);
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_INITIALIZATION_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
InitializeCriticalSection(&callback->lock);
|
|
Packit |
1fb8d4 |
callback->iface.OnDataReceived = sshagent_on_data_received;
|
|
Packit |
1fb8d4 |
callback->iface.OnClose = sshagent_on_close;
|
|
Packit |
1fb8d4 |
callback->plugin = listener_callback->plugin;
|
|
Packit |
1fb8d4 |
callback->channel_mgr = listener_callback->channel_mgr;
|
|
Packit |
1fb8d4 |
callback->channel = pChannel;
|
|
Packit |
1fb8d4 |
callback->rdpcontext = listener_callback->rdpcontext;
|
|
Packit |
1fb8d4 |
callback->thread
|
|
Packit |
1fb8d4 |
= CreateThread(NULL,
|
|
Packit |
1fb8d4 |
0,
|
|
Packit |
1fb8d4 |
sshagent_read_thread,
|
|
Packit |
1fb8d4 |
(void*) callback,
|
|
Packit |
1fb8d4 |
0,
|
|
Packit |
1fb8d4 |
NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!callback->thread)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "CreateThread failed!");
|
|
Packit |
1fb8d4 |
DeleteCriticalSection(&callback->lock);
|
|
Packit |
1fb8d4 |
free(callback);
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_INITIALIZATION_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Callback for when the plugin is initialised
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static UINT sshagent_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*) pPlugin;
|
|
Packit |
1fb8d4 |
sshagent->listener_callback = (SSHAGENT_LISTENER_CALLBACK*) calloc(1,
|
|
Packit |
1fb8d4 |
sizeof(SSHAGENT_LISTENER_CALLBACK));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!sshagent->listener_callback)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "calloc failed!");
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_NO_MEMORY;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
sshagent->listener_callback->rdpcontext = sshagent->rdpcontext;
|
|
Packit |
1fb8d4 |
sshagent->listener_callback->iface.OnNewChannelConnection = sshagent_on_new_channel_connection;
|
|
Packit |
1fb8d4 |
sshagent->listener_callback->plugin = pPlugin;
|
|
Packit |
1fb8d4 |
sshagent->listener_callback->channel_mgr = pChannelMgr;
|
|
Packit |
1fb8d4 |
sshagent->listener_callback->agent_uds_path = getenv("SSH_AUTH_SOCK");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (sshagent->listener_callback->agent_uds_path == NULL)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Environment variable $SSH_AUTH_SOCK undefined!");
|
|
Packit |
1fb8d4 |
free(sshagent->listener_callback);
|
|
Packit |
1fb8d4 |
sshagent->listener_callback = NULL;
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_INITIALIZATION_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return pChannelMgr->CreateListener(pChannelMgr, "SSHAGENT", 0,
|
|
Packit |
1fb8d4 |
(IWTSListenerCallback*) sshagent->listener_callback, NULL);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Callback for when the plugin is terminated
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
static UINT sshagent_plugin_terminated(IWTSPlugin* pPlugin)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*) pPlugin;
|
|
Packit |
1fb8d4 |
free(sshagent);
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef BUILTIN_CHANNELS
|
|
Packit |
1fb8d4 |
#define DVCPluginEntry sshagent_DVCPluginEntry
|
|
Packit |
1fb8d4 |
#else
|
|
Packit |
1fb8d4 |
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Main entry point for sshagent DVC plugin
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* @return 0 on success, otherwise a Win32 error code
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT status = CHANNEL_RC_OK;
|
|
Packit |
1fb8d4 |
SSHAGENT_PLUGIN* sshagent;
|
|
Packit |
1fb8d4 |
sshagent = (SSHAGENT_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "sshagent");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!sshagent)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
sshagent = (SSHAGENT_PLUGIN*) calloc(1, sizeof(SSHAGENT_PLUGIN));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!sshagent)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "calloc failed!");
|
|
Packit |
1fb8d4 |
return CHANNEL_RC_NO_MEMORY;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
sshagent->iface.Initialize = sshagent_plugin_initialize;
|
|
Packit |
1fb8d4 |
sshagent->iface.Connected = NULL;
|
|
Packit |
1fb8d4 |
sshagent->iface.Disconnected = NULL;
|
|
Packit |
1fb8d4 |
sshagent->iface.Terminated = sshagent_plugin_terminated;
|
|
Packit |
1fb8d4 |
sshagent->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(
|
|
Packit |
1fb8d4 |
pEntryPoints))->instance)->context;
|
|
Packit |
1fb8d4 |
status = pEntryPoints->RegisterPlugin(pEntryPoints, "sshagent", (IWTSPlugin*) sshagent);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return status;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* vim: set sw=8:ts=8:noet: */
|