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 (*pfnShadowAuthenticate)(rdpShadowSubsystem* subsystem,
|
||||
const char* user, const char* domain, const char* password);
|
||||
|
||||
typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags);
|
||||
typedef int (*pfnShadowKeyboardEvent)(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 mayInteract;
|
||||
BOOL shareSubRect;
|
||||
BOOL authentication;
|
||||
int selectedMonitor;
|
||||
RECTANGLE_16 subRect;
|
||||
char* ipcSocket;
|
||||
@ -148,6 +152,8 @@ struct _RDP_SHADOW_ENTRY_POINTS
|
||||
pfnShadowMouseEvent MouseEvent; \
|
||||
pfnShadowExtendedMouseEvent ExtendedMouseEvent; \
|
||||
\
|
||||
pfnShadowAuthenticate Authenticate; \
|
||||
\
|
||||
rdpShadowServer* server
|
||||
|
||||
struct rdp_shadow_subsystem
|
||||
|
@ -26,6 +26,22 @@ elseif(APPLE AND NOT IOS)
|
||||
set(WITH_SHADOW_MAC 1)
|
||||
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)
|
||||
set(XEXT_FEATURE_TYPE "RECOMMENDED")
|
||||
set(XEXT_FEATURE_PURPOSE "X11 extension")
|
||||
@ -188,6 +204,8 @@ elseif(WITH_SHADOW_MAC)
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_MAC_LIBS})
|
||||
endif()
|
||||
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_AUTH_LIBS})
|
||||
|
||||
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS freerdp)
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/image.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
@ -50,6 +51,156 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
|
||||
@ -1092,6 +1243,10 @@ x11ShadowSubsystem* x11_shadow_subsystem_new()
|
||||
if (!subsystem)
|
||||
return NULL;
|
||||
|
||||
#ifdef WITH_PAM
|
||||
subsystem->Authenticate = (pfnShadowAuthenticate) x11_shadow_pam_authenticate;
|
||||
#endif
|
||||
|
||||
subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) x11_shadow_input_synchronize_event;
|
||||
subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) x11_shadow_input_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)
|
||||
{
|
||||
int authStatus;
|
||||
int width, height;
|
||||
rdpSettings* settings;
|
||||
rdpShadowClient* client;
|
||||
rdpShadowSurface* lobby;
|
||||
rdpShadowServer* server;
|
||||
RECTANGLE_16 invalidRect;
|
||||
rdpShadowSubsystem* subsystem;
|
||||
|
||||
client = (rdpShadowClient*) peer->context;
|
||||
settings = peer->settings;
|
||||
server = client->server;
|
||||
subsystem = server->subsystem;
|
||||
|
||||
if (!server->shareSubRect)
|
||||
{
|
||||
@ -184,6 +187,29 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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" },
|
||||
{ "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" },
|
||||
{ "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-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" },
|
||||
@ -232,6 +233,10 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a
|
||||
server->subRect.bottom = y + h;
|
||||
server->shareSubRect = TRUE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "auth")
|
||||
{
|
||||
server->authentication = arg->Value ? TRUE : FALSE;
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
|
||||
@ -610,6 +615,12 @@ rdpShadowServer* shadow_server_new()
|
||||
server->mayView = TRUE;
|
||||
server->mayInteract = TRUE;
|
||||
|
||||
#ifdef WITH_SHADOW_X11
|
||||
server->authentication = TRUE;
|
||||
#else
|
||||
server->authentication = FALSE;
|
||||
#endif
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user