shadow: add X11 PAM authentication
This commit is contained in:
parent
315d16a978
commit
668aa17a22
@ -61,6 +61,9 @@ typedef int (*pfnShadowSubsystemStop)(rdpShadowSubsystem* subsystem);
|
|||||||
|
|
||||||
typedef int (*pfnShadowEnumMonitors)(MONITOR_DEF* monitors, int maxMonitors);
|
typedef int (*pfnShadowEnumMonitors)(MONITOR_DEF* monitors, int maxMonitors);
|
||||||
|
|
||||||
|
typedef int (*pfnShadowAuthenticate)(rdpShadowSubsystem* subsystem,
|
||||||
|
const char* user, const char* domain, const char* password);
|
||||||
|
|
||||||
typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags);
|
typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags);
|
||||||
typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
|
typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
|
||||||
typedef int (*pfnShadowUnicodeKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
|
typedef int (*pfnShadowUnicodeKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
|
||||||
@ -104,6 +107,7 @@ struct rdp_shadow_server
|
|||||||
BOOL mayView;
|
BOOL mayView;
|
||||||
BOOL mayInteract;
|
BOOL mayInteract;
|
||||||
BOOL shareSubRect;
|
BOOL shareSubRect;
|
||||||
|
BOOL authentication;
|
||||||
int selectedMonitor;
|
int selectedMonitor;
|
||||||
RECTANGLE_16 subRect;
|
RECTANGLE_16 subRect;
|
||||||
char* ipcSocket;
|
char* ipcSocket;
|
||||||
@ -148,6 +152,8 @@ struct _RDP_SHADOW_ENTRY_POINTS
|
|||||||
pfnShadowMouseEvent MouseEvent; \
|
pfnShadowMouseEvent MouseEvent; \
|
||||||
pfnShadowExtendedMouseEvent ExtendedMouseEvent; \
|
pfnShadowExtendedMouseEvent ExtendedMouseEvent; \
|
||||||
\
|
\
|
||||||
|
pfnShadowAuthenticate Authenticate; \
|
||||||
|
\
|
||||||
rdpShadowServer* server
|
rdpShadowServer* server
|
||||||
|
|
||||||
struct rdp_shadow_subsystem
|
struct rdp_shadow_subsystem
|
||||||
|
@ -26,6 +26,22 @@ elseif(APPLE AND NOT IOS)
|
|||||||
set(WITH_SHADOW_MAC 1)
|
set(WITH_SHADOW_MAC 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
|
||||||
|
if(WITH_SHADOW_X11 OR WITH_SHADOW_MAC)
|
||||||
|
set(PAM_FEATURE_TYPE "RECOMMENDED")
|
||||||
|
set(PAM_FEATURE_PURPOSE "authentication")
|
||||||
|
set(PAM_FEATURE_DESCRIPTION "user authentication")
|
||||||
|
|
||||||
|
find_feature(PAM ${PAM_FEATURE_TYPE} ${PAM_FEATURE_PURPOSE} ${PAM_FEATURE_DESCRIPTION})
|
||||||
|
|
||||||
|
if(PAM_FOUND)
|
||||||
|
add_definitions(-DWITH_PAM)
|
||||||
|
include_directories(${PAM_INCLUDE_DIR})
|
||||||
|
list(APPEND ${MODULE_PREFIX}_AUTH_LIBS ${PAM_LIBRARY})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WITH_SHADOW_X11)
|
if(WITH_SHADOW_X11)
|
||||||
set(XEXT_FEATURE_TYPE "RECOMMENDED")
|
set(XEXT_FEATURE_TYPE "RECOMMENDED")
|
||||||
set(XEXT_FEATURE_PURPOSE "X11 extension")
|
set(XEXT_FEATURE_PURPOSE "X11 extension")
|
||||||
@ -188,6 +204,8 @@ elseif(WITH_SHADOW_MAC)
|
|||||||
list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_MAC_LIBS})
|
list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_MAC_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_AUTH_LIBS})
|
||||||
|
|
||||||
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||||
|
|
||||||
list(APPEND ${MODULE_PREFIX}_LIBS freerdp)
|
list(APPEND ${MODULE_PREFIX}_LIBS freerdp)
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/path.h>
|
||||||
#include <winpr/synch.h>
|
#include <winpr/synch.h>
|
||||||
#include <winpr/image.h>
|
#include <winpr/image.h>
|
||||||
#include <winpr/sysinfo.h>
|
#include <winpr/sysinfo.h>
|
||||||
@ -50,6 +51,156 @@
|
|||||||
|
|
||||||
#define TAG SERVER_TAG("shadow.x11")
|
#define TAG SERVER_TAG("shadow.x11")
|
||||||
|
|
||||||
|
#ifdef WITH_PAM
|
||||||
|
|
||||||
|
#include <security/pam_appl.h>
|
||||||
|
|
||||||
|
struct _SHADOW_PAM_AUTH_DATA
|
||||||
|
{
|
||||||
|
const char* user;
|
||||||
|
const char* domain;
|
||||||
|
const char* password;
|
||||||
|
};
|
||||||
|
typedef struct _SHADOW_PAM_AUTH_DATA SHADOW_PAM_AUTH_DATA;
|
||||||
|
|
||||||
|
struct _SHADOW_PAM_AUTH_INFO
|
||||||
|
{
|
||||||
|
char* service_name;
|
||||||
|
pam_handle_t* handle;
|
||||||
|
struct pam_conv pamc;
|
||||||
|
SHADOW_PAM_AUTH_DATA appdata;
|
||||||
|
};
|
||||||
|
typedef struct _SHADOW_PAM_AUTH_INFO SHADOW_PAM_AUTH_INFO;
|
||||||
|
|
||||||
|
int x11_shadow_pam_conv(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int pam_status = PAM_SUCCESS;
|
||||||
|
SHADOW_PAM_AUTH_DATA* appdata;
|
||||||
|
struct pam_response* response;
|
||||||
|
|
||||||
|
appdata = (SHADOW_PAM_AUTH_DATA*) appdata_ptr;
|
||||||
|
|
||||||
|
response = (struct pam_response*) calloc(num_msg, sizeof(struct pam_response));
|
||||||
|
|
||||||
|
if (!response)
|
||||||
|
return PAM_CONV_ERR;
|
||||||
|
|
||||||
|
for (index = 0; index < num_msg; index++)
|
||||||
|
{
|
||||||
|
switch (msg[index]->msg_style)
|
||||||
|
{
|
||||||
|
case PAM_PROMPT_ECHO_ON:
|
||||||
|
response[index].resp = _strdup(appdata->user);
|
||||||
|
response[index].resp_retcode = PAM_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAM_PROMPT_ECHO_OFF:
|
||||||
|
response[index].resp = _strdup(appdata->password);
|
||||||
|
response[index].resp_retcode = PAM_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
pam_status = PAM_CONV_ERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pam_status != PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
free(response);
|
||||||
|
return pam_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*resp = response;
|
||||||
|
|
||||||
|
return pam_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
|
||||||
|
{
|
||||||
|
if (PathFileExistsA("/etc/pam.d/lightdm"))
|
||||||
|
{
|
||||||
|
info->service_name = _strdup("lightdm");
|
||||||
|
}
|
||||||
|
else if (PathFileExistsA("/etc/pam.d/gdm"))
|
||||||
|
{
|
||||||
|
info->service_name = _strdup("gdm");
|
||||||
|
}
|
||||||
|
else if (PathFileExistsA("/etc/pam.d/xdm"))
|
||||||
|
{
|
||||||
|
info->service_name = _strdup("xdm");
|
||||||
|
}
|
||||||
|
else if (PathFileExistsA("/etc/pam.d/login"))
|
||||||
|
{
|
||||||
|
info->service_name = _strdup("login");
|
||||||
|
}
|
||||||
|
else if (PathFileExistsA("/etc/pam.d/sshd"))
|
||||||
|
{
|
||||||
|
info->service_name = _strdup("sshd");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x11_shadow_pam_authenticate(x11ShadowSubsystem* subsystem, const char* user, const char* domain, const char* password)
|
||||||
|
{
|
||||||
|
int pam_status;
|
||||||
|
SHADOW_PAM_AUTH_INFO* info;
|
||||||
|
|
||||||
|
info = calloc(1, sizeof(SHADOW_PAM_AUTH_INFO));
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return PAM_CONV_ERR;
|
||||||
|
|
||||||
|
if (x11_shadow_pam_get_service_name(info) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
info->appdata.user = user;
|
||||||
|
info->appdata.domain = domain;
|
||||||
|
info->appdata.password = password;
|
||||||
|
|
||||||
|
info->pamc.conv = &x11_shadow_pam_conv;
|
||||||
|
info->pamc.appdata_ptr = &(info->appdata);
|
||||||
|
|
||||||
|
pam_status = pam_start(info->service_name, 0, &(info->pamc), &(info->handle));
|
||||||
|
|
||||||
|
if (pam_status != PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "pam_start failure: %s\n", pam_strerror(info->handle, pam_status));
|
||||||
|
free(info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pam_status = pam_authenticate(info->handle, 0);
|
||||||
|
|
||||||
|
if (pam_status != PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "pam_authenticate failure: %s\n", pam_strerror(info->handle, pam_status));
|
||||||
|
free(info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pam_status = pam_acct_mgmt(info->handle, 0);
|
||||||
|
|
||||||
|
if (pam_status != PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "pam_acct_mgmt failure: %s\n", pam_strerror(info->handle, pam_status));
|
||||||
|
free(info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(info);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void x11_shadow_input_synchronize_event(x11ShadowSubsystem* subsystem, UINT32 flags)
|
void x11_shadow_input_synchronize_event(x11ShadowSubsystem* subsystem, UINT32 flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1092,6 +1243,10 @@ x11ShadowSubsystem* x11_shadow_subsystem_new()
|
|||||||
if (!subsystem)
|
if (!subsystem)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef WITH_PAM
|
||||||
|
subsystem->Authenticate = (pfnShadowAuthenticate) x11_shadow_pam_authenticate;
|
||||||
|
#endif
|
||||||
|
|
||||||
subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) x11_shadow_input_synchronize_event;
|
subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) x11_shadow_input_synchronize_event;
|
||||||
subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) x11_shadow_input_keyboard_event;
|
subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) x11_shadow_input_keyboard_event;
|
||||||
subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) x11_shadow_input_unicode_keyboard_event;
|
subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) x11_shadow_input_unicode_keyboard_event;
|
||||||
|
@ -132,16 +132,19 @@ BOOL shadow_client_capabilities(freerdp_peer* peer)
|
|||||||
|
|
||||||
BOOL shadow_client_post_connect(freerdp_peer* peer)
|
BOOL shadow_client_post_connect(freerdp_peer* peer)
|
||||||
{
|
{
|
||||||
|
int authStatus;
|
||||||
int width, height;
|
int width, height;
|
||||||
rdpSettings* settings;
|
rdpSettings* settings;
|
||||||
rdpShadowClient* client;
|
rdpShadowClient* client;
|
||||||
rdpShadowSurface* lobby;
|
rdpShadowSurface* lobby;
|
||||||
rdpShadowServer* server;
|
rdpShadowServer* server;
|
||||||
RECTANGLE_16 invalidRect;
|
RECTANGLE_16 invalidRect;
|
||||||
|
rdpShadowSubsystem* subsystem;
|
||||||
|
|
||||||
client = (rdpShadowClient*) peer->context;
|
client = (rdpShadowClient*) peer->context;
|
||||||
settings = peer->settings;
|
settings = peer->settings;
|
||||||
server = client->server;
|
server = client->server;
|
||||||
|
subsystem = server->subsystem;
|
||||||
|
|
||||||
if (!server->shareSubRect)
|
if (!server->shareSubRect)
|
||||||
{
|
{
|
||||||
@ -184,6 +187,29 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
|
|||||||
|
|
||||||
region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect);
|
region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect);
|
||||||
|
|
||||||
|
authStatus = -1;
|
||||||
|
|
||||||
|
if (settings->Username && settings->Password)
|
||||||
|
settings->AutoLogonEnabled = TRUE;
|
||||||
|
|
||||||
|
if (settings->AutoLogonEnabled && server->authentication)
|
||||||
|
{
|
||||||
|
if (subsystem->Authenticate)
|
||||||
|
{
|
||||||
|
authStatus = subsystem->Authenticate(subsystem,
|
||||||
|
settings->Username, settings->Domain, settings->Password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server->authentication)
|
||||||
|
{
|
||||||
|
if (authStatus < 0)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "client authentication failure: %d", authStatus);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ static COMMAND_LINE_ARGUMENT_A shadow_args[] =
|
|||||||
{ "ipc-socket", COMMAND_LINE_VALUE_REQUIRED, "<ipc-socket>", NULL, NULL, -1, NULL, "Server IPC socket" },
|
{ "ipc-socket", COMMAND_LINE_VALUE_REQUIRED, "<ipc-socket>", NULL, NULL, -1, NULL, "Server IPC socket" },
|
||||||
{ "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", NULL, NULL, -1, NULL, "Select or list monitors" },
|
{ "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", NULL, NULL, -1, NULL, "Select or list monitors" },
|
||||||
{ "rect", COMMAND_LINE_VALUE_REQUIRED, "<x,y,w,h>", NULL, NULL, -1, NULL, "Select rectangle within monitor to share" },
|
{ "rect", COMMAND_LINE_VALUE_REQUIRED, "<x,y,w,h>", NULL, NULL, -1, NULL, "Select rectangle within monitor to share" },
|
||||||
|
{ "auth", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Clients must authenticate" },
|
||||||
{ "may-view", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may view without prompt" },
|
{ "may-view", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may view without prompt" },
|
||||||
{ "may-interact", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may interact without prompt" },
|
{ "may-interact", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may interact without prompt" },
|
||||||
{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" },
|
{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" },
|
||||||
@ -232,6 +233,10 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a
|
|||||||
server->subRect.bottom = y + h;
|
server->subRect.bottom = y + h;
|
||||||
server->shareSubRect = TRUE;
|
server->shareSubRect = TRUE;
|
||||||
}
|
}
|
||||||
|
CommandLineSwitchCase(arg, "auth")
|
||||||
|
{
|
||||||
|
server->authentication = arg->Value ? TRUE : FALSE;
|
||||||
|
}
|
||||||
CommandLineSwitchDefault(arg)
|
CommandLineSwitchDefault(arg)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -610,6 +615,12 @@ rdpShadowServer* shadow_server_new()
|
|||||||
server->mayView = TRUE;
|
server->mayView = TRUE;
|
||||||
server->mayInteract = TRUE;
|
server->mayInteract = TRUE;
|
||||||
|
|
||||||
|
#ifdef WITH_SHADOW_X11
|
||||||
|
server->authentication = TRUE;
|
||||||
|
#else
|
||||||
|
server->authentication = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user