Enable smartcard NLA logon

This commit is contained in:
David Fort
2022-02-01 23:23:34 +01:00
committed by akallabeth
parent a563a6836b
commit cb351a099d
29 changed files with 1532 additions and 242 deletions

View File

@@ -32,6 +32,7 @@
#include <freerdp/client.h>
#include <freerdp/utils/signal.h>
#include <freerdp/locale/keyboard.h>
#include <freerdp/utils/smartcard_cli.h>
#include <linux/input.h>
@@ -702,15 +703,14 @@ int main(int argc, char* argv[])
status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
if (status)
{
BOOL list;
rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
list = settings->ListMonitors;
if (list)
if (settings->ListMonitors)
wlf_list_monitors(wlc);
if (settings->ListSmartcards)
freerdp_smartcard_list(settings);
goto fail;
}

View File

@@ -34,6 +34,7 @@
#include <freerdp/client/cmdline.h>
#include <freerdp/client/channels.h>
#include <freerdp/channels/channels.h>
#include <freerdp/utils/smartcard_cli.h>
#include "../resource/resource.h"
@@ -103,10 +104,13 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
goto out;
status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
if (status)
{
ret = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
if (settings->ListSmartcards)
freerdp_smartcard_list(settings);
goto out;
}

View File

@@ -29,6 +29,7 @@
#include <freerdp/streamdump.h>
#include <freerdp/freerdp.h>
#include <freerdp/client/cmdline.h>
#include <freerdp/utils/smartcard_cli.h>
#include "../xf_client.h"
#include "../xfreerdp.h"
@@ -59,15 +60,14 @@ int main(int argc, char* argv[])
status = freerdp_client_settings_parse_command_line(context->settings, argc, argv, FALSE);
if (status)
{
BOOL list;
rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
list = settings->ListMonitors;
if (list)
if (settings->ListMonitors)
xf_list_monitors(xfc);
if (settings->ListSmartcards)
freerdp_smartcard_list(settings);
goto out;
}

View File

@@ -253,7 +253,6 @@ static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
if (settings->SmartcardLogon)
{
settings->NlaSecurity = FALSE; /* for now */
settings->TlsSecurity = TRUE;
settings->RedirectSmartCards = TRUE;
settings->DeviceRedirection = TRUE;
@@ -427,6 +426,7 @@ static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reaso
{
static const size_t password_size = 512;
const char* auth[] = { "Username: ", "Domain: ", "Password: " };
const char* authPin[] = { "Username: ", "Domain: ", "Pin: " };
const char* gw[] = { "GatewayUsername: ", "GatewayDomain: ", "GatewayPassword: " };
const char** prompt;
@@ -437,6 +437,9 @@ static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reaso
case AUTH_RDP:
prompt = auth;
break;
case AUTH_SMARTCARD_PIN:
prompt = authPin;
break;
case GW_AUTH_HTTP:
case GW_AUTH_RDG:
case GW_AUTH_RPC:
@@ -516,21 +519,14 @@ BOOL client_cli_authenticate_ex(freerdp* instance, char** username, char** passw
WINPR_ASSERT(password);
WINPR_ASSERT(domain);
if (instance->settings->SmartcardLogon)
{
WLog_INFO(TAG, "Authentication via smartcard");
return TRUE;
}
switch (reason)
{
case AUTH_NLA:
break;
case AUTH_TLS:
if ((*username) && (*password))
return TRUE;
break;
case AUTH_RDP:
case AUTH_SMARTCARD_PIN: /* in this case password is pin code */
if ((*username) && (*password))
return TRUE;
break;

View File

@@ -24,12 +24,13 @@
#endif
#include <ctype.h>
#include <winpr/assert.h>
#include <errno.h>
#include <winpr/assert.h>
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/path.h>
#include <winpr/ncrypt.h>
#include <freerdp/addin.h>
#include <freerdp/settings.h>
@@ -479,6 +480,22 @@ BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv,
printf("\n");
printf("Drive Redirection: /drive:home,/home/user\n");
printf("Smartcard Redirection: /smartcard:<device>\n");
printf("Smartcard logon with rdp only: /smartcard-logon [/sec:rdp]\n");
printf("Smartcard logon with Kerberos authentication: /smartcard-logon /sec:nla\n");
printf("Those options are only accepted with /smartcard-logon:\n");
printf(" PIN code: /pin:<PIN code>\n");
printf(" PKCS11 module to load: /pkcs11-module:<module>\n");
printf(" PKINIT anchors: /pkinit-anchors:<pkinit_anchors>\n");
printf(" Kerberos Ticket start time: /start-time:<delay to issue ticket>\n");
printf(" Kerberos Ticket lifetime: /lifetime:<ticket lifetime>\n");
printf(" Kerberos Ticket renewable lifetime: /renewable-lifetime:<ticket renewable "
"lifetime>\n");
/* See also http://web.mit.edu/kerberos/krb5-latest/doc/basic/date_format.html */
printf(" The delay and lifetime have the following syntax: <integer>[s|m|h|d] (for seconds, "
" minutes, hours and days)\n");
printf(" CSP Name: /csp:<csp name>\n");
printf(" Card Name: /card:<card name>\n");
printf("Serial Port Redirection: /serial:<name>,<device>,[SerCx2|SerCx|Serial],[permissive]\n");
printf("Serial Port Redirection: /serial:COM1,/dev/ttyS0\n");
printf("Parallel Port Redirection: /parallel:<name>,<device>\n");
@@ -1354,6 +1371,12 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings,
settings->ListMonitors = TRUE;
}
arg = CommandLineFindArgumentA(largs, "smartcard-list");
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
settings->ListSmartcards = TRUE;
}
arg = CommandLineFindArgumentA(largs, "kbd-scancode-list");
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
@@ -1565,7 +1588,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "v")
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "v")
{
char* p;
@@ -1848,6 +1873,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
{
settings->ListMonitors = enable;
}
CommandLineSwitchCase(arg, "smartcard-list")
{
settings->ListSmartcards = enable;
}
CommandLineSwitchCase(arg, "t")
{
if (!freerdp_settings_set_string(settings, FreeRDP_WindowTitle, arg->Value))
@@ -3239,6 +3268,59 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
}
CommandLineSwitchCase(arg, "pin")
{
if (!copy_value(arg->Value, &settings->Pin))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "pkcs11-module")
{
if (!copy_value(arg->Value, &settings->Pkcs11Module))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "pkinit-anchors")
{
if (!copy_value(arg->Value, &settings->PkinitAnchors))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "kerberos-start-time")
{
/* Let kinit parse time strings according to krb5_string_to_deltat syntax. */
if (!copy_value(arg->Value, &settings->KerberosStartTime))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "kerberos-lifetime")
{
/* Let kinit parse time strings according to krb5_string_to_deltat syntax. */
if (!copy_value(arg->Value, &settings->KerberosLifeTime))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "kerberos-renewable-lifetime")
{
/* Let kinit parse time strings according to krb5_string_to_deltat syntax. */
if (!copy_value(arg->Value, &settings->KerberosRenewableLifeTime))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "csp")
{
if (!copy_value(arg->Value, &settings->CspName))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "card")
{
if (!copy_value(arg->Value, &settings->CardName))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "reader")
{
if (!copy_value(arg->Value, &settings->ReaderName))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "container")
{
if (!copy_value(arg->Value, &settings->ContainerName))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "action-script")
{
if (!freerdp_settings_set_string(settings, FreeRDP_ActionScript, arg->Value))
@@ -3263,18 +3345,21 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
} ptr;
settings->SmartcardLogon = TRUE;
ptr.p = CommandLineParseCommaSeparatedValuesEx("smartcard-logon", arg->Value, &count);
if (ptr.pc)
{
size_t x;
settings->SmartcardEmulation = TRUE;
settings->SmartcardEmulation = (count > 1);
for (x = 1; x < count; x++)
{
const char* cur = ptr.pc[x];
if (strncmp("cert:", cur, 5) == 0)
{
const char* f = &cur[5];
if (!read_pem_file(settings, FreeRDP_SmartcardCertificate, f))
settings->SmartcardCertificateFile = strdup(f);
if (!settings->SmartcardCertificateFile ||
!read_pem_file(settings, FreeRDP_SmartcardCertificate, f))
{
free(ptr.p);
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
@@ -3283,7 +3368,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
else if (strncmp("key:", cur, 4) == 0)
{
const char* f = &cur[4];
if (!read_pem_file(settings, FreeRDP_SmartcardPrivateKey, f))
settings->SmartcardPrivateKeyFile = strdup(f);
if (!settings->SmartcardPrivateKeyFile ||
!read_pem_file(settings, FreeRDP_SmartcardPrivateKey, f))
{
free(ptr.p);
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
@@ -3307,7 +3394,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
}
free(ptr.p);
}
CommandLineSwitchCase(arg, "tune")
{
size_t x, count;
@@ -3480,7 +3566,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
}
arg = CommandLineFindArgumentA(largs, "port");
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
{
LONGLONG val;
@@ -3492,14 +3577,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
}
arg = CommandLineFindArgumentA(largs, "p");
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
{
FillMemory(arg->Value, strlen(arg->Value), '*');
}
arg = CommandLineFindArgumentA(largs, "pin");
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
{
FillMemory(arg->Value, strlen(arg->Value), '*');
}
arg = CommandLineFindArgumentA(largs, "gp");
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
{
FillMemory(arg->Value, strlen(arg->Value), '*');

View File

@@ -224,6 +224,12 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
{ "kbd-unicode", COMMAND_LINE_VALUE_FLAG, "", NULL, NULL, -1, NULL,
"Send unicode symbols, e.g. use the local keyboard map. ATTENTION: Does not work with every "
"RDP server!" },
{ "kerberos-start-time", COMMAND_LINE_VALUE_OPTIONAL, "<start time>", NULL, NULL, -1, NULL,
"Kerberos Ticket start time" },
{ "kerberos-lifetime", COMMAND_LINE_VALUE_OPTIONAL, "<lifetime>", NULL, NULL, -1, NULL,
"Kerberos Ticket lifetime" },
{ "kerberos-renewable-lifetime", COMMAND_LINE_VALUE_OPTIONAL, "<renewable lifetime>", NULL,
NULL, -1, NULL, "Kerberos Ticket renewable lifetime" },
{ "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "<info-string>", NULL, NULL, -1, NULL,
"Load balance info" },
{ "log-filters", COMMAND_LINE_VALUE_REQUIRED, "<tag>:<level>[,<tag>:<level>[,...]]", NULL, NULL,
@@ -239,6 +245,8 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
{ "microphone", COMMAND_LINE_VALUE_OPTIONAL,
"[sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,][channel:<channel>]", NULL, NULL, -1,
"mic", "Audio input (microphone)" },
{ "smartcard-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL,
"List smartcard informations" },
{ "monitor-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL,
"List detected monitors" },
{ "monitors", COMMAND_LINE_VALUE_REQUIRED, "<id>[,<id>[,...]]", NULL, NULL, -1, NULL,
@@ -278,8 +286,19 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
"Use smart card authentication with password as smart card PIN" },
{ "pcb", COMMAND_LINE_VALUE_REQUIRED, "<blob>", NULL, NULL, -1, NULL, "Preconnection Blob" },
{ "pcid", COMMAND_LINE_VALUE_REQUIRED, "<id>", NULL, NULL, -1, NULL, "Preconnection Id" },
{ "card", COMMAND_LINE_VALUE_OPTIONAL, "<card name>", NULL, NULL, -1, NULL, "Card name" },
{ "csp", COMMAND_LINE_VALUE_OPTIONAL, "<csp name>", NULL, NULL, -1, NULL, "CSP Name" },
{ "reader", COMMAND_LINE_VALUE_OPTIONAL, "<reader name>", NULL, NULL, -1, NULL,
"Card reader name" },
{ "container", COMMAND_LINE_VALUE_OPTIONAL, "<container name>", NULL, NULL, -1, NULL,
"Container name" },
{ "pin", COMMAND_LINE_VALUE_REQUIRED, "<PIN code>", NULL, NULL, -1, NULL, "PIN code" },
{ "pheight", COMMAND_LINE_VALUE_REQUIRED, "<height>", NULL, NULL, -1, NULL,
"Physical height of display (in millimeters)" },
{ "pkcs11-module", COMMAND_LINE_VALUE_OPTIONAL, "<module>", NULL, NULL, -1, NULL,
"Module PKCS11" },
{ "pkinit-anchors", COMMAND_LINE_VALUE_OPTIONAL, "<pkinit anchors>", NULL, NULL, -1, NULL,
"PKINIT anchors" },
{ "play-rfx", COMMAND_LINE_VALUE_REQUIRED, "<pcap-file>", NULL, NULL, -1, NULL,
"Replay rfx pcap file" },
{ "port", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, "Server port" },
@@ -339,9 +358,7 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
{ "smartcard", COMMAND_LINE_VALUE_OPTIONAL, "<str>[,<str>...]", NULL, NULL, -1, NULL,
"Redirect the smartcard devices containing any of the <str> in their names." },
{ "smartcard-logon", COMMAND_LINE_VALUE_OPTIONAL, "[cert:<path>,key:<key>,pin:<pin>]", NULL,
NULL, -1, NULL,
"Activates Smartcard (optional certificate) Logon authentication. (EXPERIMENTAL: NLA not "
"supported)" },
NULL, -1, NULL, "Activates Smartcard (optional certificate) Logon authentication." },
{ "sound", COMMAND_LINE_VALUE_OPTIONAL,
"[sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,][channel:<channel>,][latency:<"
"latency>,][quality:<quality>]",

View File

@@ -54,6 +54,7 @@ extern "C"
typedef struct crypto_cert_struct* CryptoCert;
FREERDP_API CryptoCert crypto_cert_read(const BYTE* data, UINT32 length);
FREERDP_API CryptoCert crypto_cert_pem_read(const char* data);
FREERDP_API BYTE* crypto_cert_hash(X509* xcert, const char* hash, UINT32* length);
FREERDP_API char* crypto_cert_fingerprint_by_hash(X509* xcert, const char* hash);
FREERDP_API char* crypto_cert_fingerprint_by_hash_ex(X509* xcert, const char* hash,

View File

@@ -104,7 +104,8 @@ extern "C"
AUTH_RDP,
GW_AUTH_HTTP,
GW_AUTH_RDG,
GW_AUTH_RPC
GW_AUTH_RPC,
AUTH_SMARTCARD_PIN
} rdp_auth_reason;
typedef BOOL (*pContextNew)(freerdp* instance, rdpContext* context);

View File

@@ -663,8 +663,22 @@ typedef struct
#define FreeRDP_SmartcardPrivateKey (1286)
#define FreeRDP_SmartcardPin (1287)
#define FreeRDP_SmartcardEmulation (1288)
#define FreeRDP_SmartcardCertificateFile (1289)
#define FreeRDP_SmartcardPrivateKeyFile (1290)
#define FreeRDP_Pkcs11Module (1291)
#define FreeRDP_Pin (1292)
#define FreeRDP_KeySpec (1293)
#define FreeRDP_CardName (1294)
#define FreeRDP_ReaderName (1295)
#define FreeRDP_ContainerName (1296)
#define FreeRDP_CspName (1297)
#define FreeRDP_PkinitAnchors (1298)
#define FreeRDP_ListSmartcards (1299)
#define FreeRDP_KerberosKdc (1344)
#define FreeRDP_KerberosRealm (1345)
#define FreeRDP_KerberosStartTime (1346)
#define FreeRDP_KerberosLifeTime (1347)
#define FreeRDP_KerberosRenewableLifeTime (1348)
#define FreeRDP_IgnoreCertificate (1408)
#define FreeRDP_CertificateName (1409)
#define FreeRDP_CertificateFile (1410)
@@ -1143,19 +1157,33 @@ struct rdp_settings
ALIGN64 UINT32 Password51Length; /* 1281 */
ALIGN64 BOOL SmartcardLogon; /* 1282 */
ALIGN64 BOOL PromptForCredentials; /* 1283 */
UINT64 padding1284[1285 - 1284]; /* 1284 */
/* Settings used for smartcard emulation */
UINT64 padding1284[1285 - 1284]; /* 1284 */
ALIGN64 char* SmartcardCertificate; /* 1285 */
ALIGN64 char* SmartcardPrivateKey; /* 1286 */
ALIGN64 char* SmartcardPin; /* 1287 */
ALIGN64 BOOL SmartcardEmulation; /* 1288 */
UINT64 padding1344[1344 - 1289]; /* 1289 */
ALIGN64 char* SmartcardCertificate; /* 1285 */
ALIGN64 char* SmartcardPrivateKey; /* 1286 */
ALIGN64 char* SmartcardPin; /* 1287 */
ALIGN64 BOOL SmartcardEmulation; /* 1288 */
ALIGN64 char* SmartcardCertificateFile; /* 1289 */
ALIGN64 char* SmartcardPrivateKeyFile; /* 1290 */
ALIGN64 char* Pkcs11Module; /* 1291 */
ALIGN64 char* Pin; /* 1292 */
ALIGN64 UINT32 KeySpec; /* 1293 */
ALIGN64 char* CardName; /* 1294 */
ALIGN64 char* ReaderName; /* 1295 */
ALIGN64 char* ContainerName; /* 1296 */
ALIGN64 char* CspName; /* 1297 */
ALIGN64 char* PkinitAnchors; /* 1298 */
ALIGN64 BOOL ListSmartcards; /* 1299 */
UINT64 padding1344[1344 - 1300]; /* 1300 */
/* Kerberos Authentication */
ALIGN64 char* KerberosKdc; /* 1344 */
ALIGN64 char* KerberosRealm; /* 1345 */
UINT64 padding1408[1408 - 1346]; /* 1346 */
ALIGN64 char* KerberosKdc; /* 1344 */
ALIGN64 char* KerberosRealm; /* 1345 */
ALIGN64 char* KerberosStartTime; /* 1346 */
ALIGN64 char* KerberosLifeTime; /* 1347 */
ALIGN64 char* KerberosRenewableLifeTime; /* 1348 */
UINT64 padding1408[1408 - 1349]; /* 1349 */
/* Server Certificate */
ALIGN64 BOOL IgnoreCertificate; /* 1408 */

View File

@@ -0,0 +1,37 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Smartcard client functions
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* 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.
*/
#ifndef UTILS_SMARTCARD_CLI_H__
#define UTILS_SMARTCARD_CLI_H__
#include <freerdp/api.h>
#include <freerdp/settings.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
FREERDP_API BOOL freerdp_smartcard_list(rdpSettings* settings);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* UTILS_SMARTCARD_CLI_H__ */

View File

@@ -291,6 +291,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, size_t id)
case FreeRDP_ListMonitors:
return settings->ListMonitors;
case FreeRDP_ListSmartcards:
return settings->ListSmartcards;
case FreeRDP_LocalConnection:
return settings->LocalConnection;
@@ -920,6 +923,10 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, size_t id, BOOL val)
settings->ListMonitors = cnv.c;
break;
case FreeRDP_ListSmartcards:
settings->ListSmartcards = cnv.c;
break;
case FreeRDP_LocalConnection:
settings->LocalConnection = cnv.c;
break;
@@ -1502,6 +1509,9 @@ UINT32 freerdp_settings_get_uint32(const rdpSettings* settings, size_t id)
case FreeRDP_JpegQuality:
return settings->JpegQuality;
case FreeRDP_KeySpec:
return settings->KeySpec;
case FreeRDP_KeyboardCodePage:
return settings->KeyboardCodePage;
@@ -1910,6 +1920,10 @@ BOOL freerdp_settings_set_uint32(rdpSettings* settings, size_t id, UINT32 val)
settings->JpegQuality = cnv.c;
break;
case FreeRDP_KeySpec:
settings->KeySpec = cnv.c;
break;
case FreeRDP_KeyboardCodePage:
settings->KeyboardCodePage = cnv.c;
break;
@@ -2340,6 +2354,9 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_AuthenticationServiceClass:
return settings->AuthenticationServiceClass;
case FreeRDP_CardName:
return settings->CardName;
case FreeRDP_CertificateAcceptedFingerprints:
return settings->CertificateAcceptedFingerprints;
@@ -2373,6 +2390,12 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_ConnectionFile:
return settings->ConnectionFile;
case FreeRDP_ContainerName:
return settings->ContainerName;
case FreeRDP_CspName:
return settings->CspName;
case FreeRDP_CurrentPath:
return settings->CurrentPath;
@@ -2415,9 +2438,18 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_KerberosKdc:
return settings->KerberosKdc;
case FreeRDP_KerberosLifeTime:
return settings->KerberosLifeTime;
case FreeRDP_KerberosRealm:
return settings->KerberosRealm;
case FreeRDP_KerberosRenewableLifeTime:
return settings->KerberosRenewableLifeTime;
case FreeRDP_KerberosStartTime:
return settings->KerberosStartTime;
case FreeRDP_KeyboardRemappingList:
return settings->KeyboardRemappingList;
@@ -2430,6 +2462,15 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_PasswordHash:
return settings->PasswordHash;
case FreeRDP_Pin:
return settings->Pin;
case FreeRDP_Pkcs11Module:
return settings->Pkcs11Module;
case FreeRDP_PkinitAnchors:
return settings->PkinitAnchors;
case FreeRDP_PlayRemoteFxFile:
return settings->PlayRemoteFxFile;
@@ -2460,6 +2501,9 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_RdpKeyFile:
return settings->RdpKeyFile;
case FreeRDP_ReaderName:
return settings->ReaderName;
case FreeRDP_RedirectionAcceptedCert:
return settings->RedirectionAcceptedCert;
@@ -2517,12 +2561,18 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
case FreeRDP_SmartcardCertificate:
return settings->SmartcardCertificate;
case FreeRDP_SmartcardCertificateFile:
return settings->SmartcardCertificateFile;
case FreeRDP_SmartcardPin:
return settings->SmartcardPin;
case FreeRDP_SmartcardPrivateKey:
return settings->SmartcardPrivateKey;
case FreeRDP_SmartcardPrivateKeyFile:
return settings->SmartcardPrivateKeyFile;
case FreeRDP_TargetNetAddress:
return settings->TargetNetAddress;
@@ -2568,6 +2618,9 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_AuthenticationServiceClass:
return settings->AuthenticationServiceClass;
case FreeRDP_CardName:
return settings->CardName;
case FreeRDP_CertificateAcceptedFingerprints:
return settings->CertificateAcceptedFingerprints;
@@ -2601,6 +2654,12 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_ConnectionFile:
return settings->ConnectionFile;
case FreeRDP_ContainerName:
return settings->ContainerName;
case FreeRDP_CspName:
return settings->CspName;
case FreeRDP_CurrentPath:
return settings->CurrentPath;
@@ -2643,9 +2702,18 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_KerberosKdc:
return settings->KerberosKdc;
case FreeRDP_KerberosLifeTime:
return settings->KerberosLifeTime;
case FreeRDP_KerberosRealm:
return settings->KerberosRealm;
case FreeRDP_KerberosRenewableLifeTime:
return settings->KerberosRenewableLifeTime;
case FreeRDP_KerberosStartTime:
return settings->KerberosStartTime;
case FreeRDP_KeyboardRemappingList:
return settings->KeyboardRemappingList;
@@ -2658,6 +2726,15 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_PasswordHash:
return settings->PasswordHash;
case FreeRDP_Pin:
return settings->Pin;
case FreeRDP_Pkcs11Module:
return settings->Pkcs11Module;
case FreeRDP_PkinitAnchors:
return settings->PkinitAnchors;
case FreeRDP_PlayRemoteFxFile:
return settings->PlayRemoteFxFile;
@@ -2688,6 +2765,9 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_RdpKeyFile:
return settings->RdpKeyFile;
case FreeRDP_ReaderName:
return settings->ReaderName;
case FreeRDP_RedirectionAcceptedCert:
return settings->RedirectionAcceptedCert;
@@ -2745,9 +2825,18 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
case FreeRDP_SmartcardCertificate:
return settings->SmartcardCertificate;
case FreeRDP_SmartcardCertificateFile:
return settings->SmartcardCertificateFile;
case FreeRDP_SmartcardPin:
return settings->SmartcardPin;
case FreeRDP_SmartcardPrivateKey:
return settings->SmartcardPrivateKey;
case FreeRDP_SmartcardPrivateKeyFile:
return settings->SmartcardPrivateKeyFile;
case FreeRDP_TargetNetAddress:
return settings->TargetNetAddress;
@@ -2803,6 +2892,9 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_AuthenticationServiceClass:
return update_string(&settings->AuthenticationServiceClass, cnv.cc, len, cleanup);
case FreeRDP_CardName:
return update_string(&settings->CardName, cnv.cc, len, cleanup);
case FreeRDP_CertificateAcceptedFingerprints:
return update_string(&settings->CertificateAcceptedFingerprints, cnv.cc, len, cleanup);
@@ -2836,6 +2928,12 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_ConnectionFile:
return update_string(&settings->ConnectionFile, cnv.cc, len, cleanup);
case FreeRDP_ContainerName:
return update_string(&settings->ContainerName, cnv.cc, len, cleanup);
case FreeRDP_CspName:
return update_string(&settings->CspName, cnv.cc, len, cleanup);
case FreeRDP_CurrentPath:
return update_string(&settings->CurrentPath, cnv.cc, len, cleanup);
@@ -2878,9 +2976,18 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_KerberosKdc:
return update_string(&settings->KerberosKdc, cnv.cc, len, cleanup);
case FreeRDP_KerberosLifeTime:
return update_string(&settings->KerberosLifeTime, cnv.cc, len, cleanup);
case FreeRDP_KerberosRealm:
return update_string(&settings->KerberosRealm, cnv.cc, len, cleanup);
case FreeRDP_KerberosRenewableLifeTime:
return update_string(&settings->KerberosRenewableLifeTime, cnv.cc, len, cleanup);
case FreeRDP_KerberosStartTime:
return update_string(&settings->KerberosStartTime, cnv.cc, len, cleanup);
case FreeRDP_KeyboardRemappingList:
return update_string(&settings->KeyboardRemappingList, cnv.cc, len, cleanup);
@@ -2893,6 +3000,15 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_PasswordHash:
return update_string(&settings->PasswordHash, cnv.cc, len, cleanup);
case FreeRDP_Pin:
return update_string(&settings->Pin, cnv.cc, len, cleanup);
case FreeRDP_Pkcs11Module:
return update_string(&settings->Pkcs11Module, cnv.cc, len, cleanup);
case FreeRDP_PkinitAnchors:
return update_string(&settings->PkinitAnchors, cnv.cc, len, cleanup);
case FreeRDP_PlayRemoteFxFile:
return update_string(&settings->PlayRemoteFxFile, cnv.cc, len, cleanup);
@@ -2923,6 +3039,9 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_RdpKeyFile:
return update_string(&settings->RdpKeyFile, cnv.cc, len, cleanup);
case FreeRDP_ReaderName:
return update_string(&settings->ReaderName, cnv.cc, len, cleanup);
case FreeRDP_RedirectionAcceptedCert:
return update_string(&settings->RedirectionAcceptedCert, cnv.cc, len, cleanup);
@@ -2980,12 +3099,18 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char*
case FreeRDP_SmartcardCertificate:
return update_string(&settings->SmartcardCertificate, cnv.cc, len, cleanup);
case FreeRDP_SmartcardCertificateFile:
return update_string(&settings->SmartcardCertificateFile, cnv.cc, len, cleanup);
case FreeRDP_SmartcardPin:
return update_string(&settings->SmartcardPin, cnv.cc, len, cleanup);
case FreeRDP_SmartcardPrivateKey:
return update_string(&settings->SmartcardPrivateKey, cnv.cc, len, cleanup);
case FreeRDP_SmartcardPrivateKeyFile:
return update_string(&settings->SmartcardPrivateKeyFile, cnv.cc, len, cleanup);
case FreeRDP_TargetNetAddress:
return update_string(&settings->TargetNetAddress, cnv.cc, len, cleanup);

View File

@@ -100,6 +100,7 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_IgnoreCertificate, 0, "FreeRDP_IgnoreCertificate" },
{ FreeRDP_JpegCodec, 0, "FreeRDP_JpegCodec" },
{ FreeRDP_ListMonitors, 0, "FreeRDP_ListMonitors" },
{ FreeRDP_ListSmartcards, 0, "FreeRDP_ListSmartcards" },
{ FreeRDP_LocalConnection, 0, "FreeRDP_LocalConnection" },
{ FreeRDP_LogonErrors, 0, "FreeRDP_LogonErrors" },
{ FreeRDP_LogonNotify, 0, "FreeRDP_LogonNotify" },
@@ -235,6 +236,7 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_GlyphSupportLevel, 3, "FreeRDP_GlyphSupportLevel" },
{ FreeRDP_JpegCodecId, 3, "FreeRDP_JpegCodecId" },
{ FreeRDP_JpegQuality, 3, "FreeRDP_JpegQuality" },
{ FreeRDP_KeySpec, 3, "FreeRDP_KeySpec" },
{ FreeRDP_KeyboardCodePage, 3, "FreeRDP_KeyboardCodePage" },
{ FreeRDP_KeyboardFunctionKey, 3, "FreeRDP_KeyboardFunctionKey" },
{ FreeRDP_KeyboardHook, 3, "FreeRDP_KeyboardHook" },
@@ -313,6 +315,7 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_AlternateShell, 7, "FreeRDP_AlternateShell" },
{ FreeRDP_AssistanceFile, 7, "FreeRDP_AssistanceFile" },
{ FreeRDP_AuthenticationServiceClass, 7, "FreeRDP_AuthenticationServiceClass" },
{ FreeRDP_CardName, 7, "FreeRDP_CardName" },
{ FreeRDP_CertificateAcceptedFingerprints, 7, "FreeRDP_CertificateAcceptedFingerprints" },
{ FreeRDP_CertificateContent, 7, "FreeRDP_CertificateContent" },
{ FreeRDP_CertificateFile, 7, "FreeRDP_CertificateFile" },
@@ -324,6 +327,8 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_ComputerName, 7, "FreeRDP_ComputerName" },
{ FreeRDP_ConfigPath, 7, "FreeRDP_ConfigPath" },
{ FreeRDP_ConnectionFile, 7, "FreeRDP_ConnectionFile" },
{ FreeRDP_ContainerName, 7, "FreeRDP_ContainerName" },
{ FreeRDP_CspName, 7, "FreeRDP_CspName" },
{ FreeRDP_CurrentPath, 7, "FreeRDP_CurrentPath" },
{ FreeRDP_Domain, 7, "FreeRDP_Domain" },
{ FreeRDP_DrivesToRedirect, 7, "FreeRDP_DrivesToRedirect" },
@@ -338,11 +343,17 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_HomePath, 7, "FreeRDP_HomePath" },
{ FreeRDP_ImeFileName, 7, "FreeRDP_ImeFileName" },
{ FreeRDP_KerberosKdc, 7, "FreeRDP_KerberosKdc" },
{ FreeRDP_KerberosLifeTime, 7, "FreeRDP_KerberosLifeTime" },
{ FreeRDP_KerberosRealm, 7, "FreeRDP_KerberosRealm" },
{ FreeRDP_KerberosRenewableLifeTime, 7, "FreeRDP_KerberosRenewableLifeTime" },
{ FreeRDP_KerberosStartTime, 7, "FreeRDP_KerberosStartTime" },
{ FreeRDP_KeyboardRemappingList, 7, "FreeRDP_KeyboardRemappingList" },
{ FreeRDP_NtlmSamFile, 7, "FreeRDP_NtlmSamFile" },
{ FreeRDP_Password, 7, "FreeRDP_Password" },
{ FreeRDP_PasswordHash, 7, "FreeRDP_PasswordHash" },
{ FreeRDP_Pin, 7, "FreeRDP_Pin" },
{ FreeRDP_Pkcs11Module, 7, "FreeRDP_Pkcs11Module" },
{ FreeRDP_PkinitAnchors, 7, "FreeRDP_PkinitAnchors" },
{ FreeRDP_PlayRemoteFxFile, 7, "FreeRDP_PlayRemoteFxFile" },
{ FreeRDP_PreconnectionBlob, 7, "FreeRDP_PreconnectionBlob" },
{ FreeRDP_PrivateKeyContent, 7, "FreeRDP_PrivateKeyContent" },
@@ -353,6 +364,7 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_RDP2TCPArgs, 7, "FreeRDP_RDP2TCPArgs" },
{ FreeRDP_RdpKeyContent, 7, "FreeRDP_RdpKeyContent" },
{ FreeRDP_RdpKeyFile, 7, "FreeRDP_RdpKeyFile" },
{ FreeRDP_ReaderName, 7, "FreeRDP_ReaderName" },
{ FreeRDP_RedirectionAcceptedCert, 7, "FreeRDP_RedirectionAcceptedCert" },
{ FreeRDP_RedirectionDomain, 7, "FreeRDP_RedirectionDomain" },
{ FreeRDP_RedirectionTargetFQDN, 7, "FreeRDP_RedirectionTargetFQDN" },
@@ -372,8 +384,10 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_ServerHostname, 7, "FreeRDP_ServerHostname" },
{ FreeRDP_ShellWorkingDirectory, 7, "FreeRDP_ShellWorkingDirectory" },
{ FreeRDP_SmartcardCertificate, 7, "FreeRDP_SmartcardCertificate" },
{ FreeRDP_SmartcardCertificateFile, 7, "FreeRDP_SmartcardCertificateFile" },
{ FreeRDP_SmartcardPin, 7, "FreeRDP_SmartcardPin" },
{ FreeRDP_SmartcardPrivateKey, 7, "FreeRDP_SmartcardPrivateKey" },
{ FreeRDP_SmartcardPrivateKeyFile, 7, "FreeRDP_SmartcardPrivateKeyFile" },
{ FreeRDP_TargetNetAddress, 7, "FreeRDP_TargetNetAddress" },
{ FreeRDP_TransportDumpFile, 7, "FreeRDP_TransportDumpFile" },
{ FreeRDP_Username, 7, "FreeRDP_Username" },

View File

@@ -63,6 +63,10 @@ set(${MODULE_PREFIX}_SRCS
mcs.h
nla.c
nla.h
smartcardlogon.c
smartcardlogon.h
tscredentials.c
tscredentials.h
nego.c
nego.h
info.c

View File

@@ -42,9 +42,13 @@
#include <winpr/dsparse.h>
#include <winpr/library.h>
#include <winpr/registry.h>
#include <winpr/ncrypt.h>
#include <winpr/cred.h>
#include "nla.h"
#include "utils.h"
#include "tscredentials.h"
#include "smartcardlogon.h"
#define TAG FREERDP_TAG("core.nla")
@@ -134,7 +138,11 @@ struct rdp_nla
SecBuffer tsCredentials;
LPTSTR ServicePrincipalName;
void* identityPtr;
SEC_WINNT_AUTH_IDENTITY* identity;
SEC_WINNT_AUTH_IDENTITY_EXW identityEx;
SEC_WINNT_AUTH_IDENTITY_WINPRA identityWinPr;
SEC_WINPR_KERBEROS_SETTINGS kerberosSettings;
PSecurityFunctionTable table;
SecPkgContext_Sizes ContextSizes;
};
@@ -386,6 +394,7 @@ static SECURITY_STATUS nla_decrypt(rdpNla* nla, SecBuffer* buffer, size_t header
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Buffers[0].cbBuffer = (ULONG)headerLength;
Buffers[0].pvBuffer = &((BYTE*)buffer->pvBuffer)[0];
Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
Buffers[1].cbBuffer = (ULONG)(buffer->cbBuffer - headerLength);
Buffers[1].pvBuffer = &((BYTE*)buffer->pvBuffer)[headerLength];
@@ -430,6 +439,7 @@ static SECURITY_STATUS nla_encrypt(rdpNla* nla, SecBuffer* buffer, size_t header
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Buffers[0].cbBuffer = (ULONG)headerLength;
Buffers[0].pvBuffer = &((BYTE*)buffer->pvBuffer)[0];
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].cbBuffer = (ULONG)(buffer->cbBuffer - headerLength);
Buffers[1].pvBuffer = &((BYTE*)buffer->pvBuffer)[headerLength];
@@ -526,29 +536,218 @@ void nla_identity_free(SEC_WINNT_AUTH_IDENTITY* identity)
free(identity);
}
/**
* Initialize NTLM/Kerberos SSP authentication module (client).
* @param credssp
*/
static int nla_client_init(rdpNla* nla)
static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
{
char* spn;
size_t length;
rdpTls* tls = NULL;
BOOL PromptPassword = FALSE;
freerdp* instance = nla->instance;
#define MAX_SC_CERTS 64
SmartcardCert certs[MAX_SC_CERTS];
DWORD count, i = 0;
rdpSettings* settings = nla->settings;
SEC_WINPR_KERBEROS_SETTINGS* kerbSettings = &nla->kerberosSettings;
BOOL ret = FALSE;
if (!settings->CspName)
{
settings->CspName = strdup(MS_SCARD_PROV_A);
if (!settings->CspName)
{
WLog_ERR(TAG, "unable to set CSP name");
return FALSE;
}
}
if (settings->PkinitAnchors)
{
kerbSettings->pkinitX509Anchors = _strdup(settings->PkinitAnchors);
if (!kerbSettings->pkinitX509Anchors)
{
WLog_ERR(TAG, "error setting X509 anchors");
return FALSE;
}
}
if (!smartcard_enumerateCerts(settings, certs, MAX_SC_CERTS, &count))
{
WLog_ERR(TAG, "unable to list smartcard certificates");
return FALSE;
}
if (!count)
{
WLog_ERR(TAG, "no smartcard certificates found");
return FALSE;
}
if (count != 1)
goto setup_pin;
/*
* just one result let's try to fill missing parameters
*/
if (!settings->Username && certs[0].userHint)
{
settings->Username = strdup(certs[0].userHint);
if (!settings->Username)
{
WLog_ERR(TAG, "unable to copy certificate username");
goto out;
}
}
if (!settings->Domain && certs[0].domainHint)
{
settings->Domain = strdup(certs[0].domainHint);
if (!settings->Domain)
{
WLog_ERR(TAG, "unable to copy certificate domain");
goto out;
}
}
if (!settings->ReaderName && certs[0].reader)
{
if (ConvertFromUnicode(CP_UTF8, 0, certs[0].reader, -1, &settings->ReaderName, 0, NULL,
NULL) < 0)
{
WLog_ERR(TAG, "unable to copy reader name");
goto out;
}
}
if (!settings->ContainerName && certs[0].containerName)
{
settings->ContainerName = strdup(certs[0].containerName);
if (!settings->ContainerName)
{
WLog_ERR(TAG, "unable to copy container name");
goto out;
}
}
memcpy(nla->kerberosSettings.certSha1, certs[0].sha1Hash,
sizeof(nla->kerberosSettings.certSha1));
#ifndef _WIN32
if (certs[0].pkinitArgs)
{
kerbSettings->pkinitX509Identity = strdup(certs[0].pkinitArgs);
if (!kerbSettings->pkinitX509Identity)
{
WLog_ERR(TAG, "unable to copy pkinitArgs");
goto out;
}
}
#endif /* _WIN32 */
setup_pin:
if (!settings->Pin)
{
if (settings->SmartcardEmulation)
{
const char* dupSrc = settings->SmartcardPin;
if (!dupSrc)
dupSrc = "";
settings->Pin = strdup(dupSrc);
if (!settings->Pin)
{
WLog_ERR(TAG, "error setting pin");
return FALSE;
}
}
else
{
freerdp* instance = nla->instance;
if (!instance->AuthenticateEx)
{
WLog_ERR(TAG, "no pin configured and no instance->AuthenticateEx callback");
return TRUE;
}
if (!instance->AuthenticateEx(instance, &settings->Username, &settings->Pin,
&settings->Domain, AUTH_SMARTCARD_PIN))
{
WLog_ERR(TAG, "no pin code entered");
return TRUE;
}
}
}
ret = TRUE;
out:
for (i = 0; i < count; i++)
smartcardCert_Free(&certs[i]);
return ret;
}
static BOOL nla_client_setup_identity(rdpNla* nla)
{
WINPR_SAM* sam;
WINPR_SAM_ENTRY* entry;
nla_set_state(nla, NLA_STATE_INITIAL);
BOOL PromptPassword = FALSE;
rdpSettings* settings = nla->settings;
freerdp* instance = nla->instance;
if (settings->RestrictedAdminModeRequired)
settings->DisableCredentialsDelegation = TRUE;
if (settings->SmartcardLogon)
{
#ifdef _WIN32
{
SEC_WINNT_AUTH_IDENTITY_EXW* identityEx;
CERT_CREDENTIAL_INFO certInfo = { sizeof(CERT_CREDENTIAL_INFO), { 0 } };
LPWSTR marshalledCredentials;
if (utils_str_is_empty(settings->Username) ||
(utils_str_is_empty(settings->Password) &&
utils_str_is_empty((const char*)settings->RedirectionPassword)))
identityEx = &nla->identityEx;
memcpy(certInfo.rgbHashOfCert, nla->kerberosSettings.certSha1,
sizeof(certInfo.rgbHashOfCert));
if (!CredMarshalCredentialW(CertCredential, &certInfo, &marshalledCredentials))
{
WLog_ERR(TAG, "error marshalling cert credentials");
return FALSE;
}
identityEx->Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
identityEx->Length = sizeof(*identityEx);
identityEx->User = (PUSHORT)marshalledCredentials;
identityEx->UserLength = _wcslen(marshalledCredentials);
if (ConvertToUnicode(CP_UTF8, 0, settings->Pin, -1, &identityEx->Password, 0) <= 0)
return FALSE;
identityEx->PasswordLength = strlen(settings->Pin);
identityEx->Domain = NULL;
identityEx->DomainLength = 0;
identityEx->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
identityEx->PackageList = NULL;
identityEx->PackageListLength = 0;
nla->identityPtr = identityEx;
}
#else
{
SEC_WINNT_AUTH_IDENTITY_EXA* identityEx = &nla->identityWinPr.identityEx;
identityEx->Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
identityEx->Length = sizeof(nla->identityWinPr);
identityEx->User = (BYTE*)settings->Username;
identityEx->UserLength = strlen(settings->Username);
identityEx->Domain = (BYTE*)settings->Domain;
identityEx->DomainLength = strlen(settings->Domain);
identityEx->Password = (BYTE*)strdup(settings->Pin);
identityEx->PasswordLength = strlen(settings->Pin);
identityEx->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
identityEx->PackageList = NULL;
identityEx->PackageListLength = 0;
nla->identityPtr = &nla->identityWinPr;
} /* smartcard logon */
#endif /* _WIN32 */
return TRUE;
}
/* */
if ((utils_str_is_empty(settings->Username) ||
(utils_str_is_empty(settings->Password) &&
utils_str_is_empty((const char*)settings->RedirectionPassword))))
{
PromptPassword = TRUE;
}
@@ -556,11 +755,9 @@ static int nla_client_init(rdpNla* nla)
if (PromptPassword && !utils_str_is_empty(settings->Username))
{
sam = SamOpen(NULL, TRUE);
if (sam)
{
entry = SamLookupUserA(sam, settings->Username, strlen(settings->Username), NULL, 0);
if (entry)
{
/**
@@ -576,7 +773,6 @@ static int nla_client_init(rdpNla* nla)
}
#ifndef _WIN32
if (PromptPassword)
{
if (settings->RestrictedAdminModeRequired)
@@ -585,7 +781,6 @@ static int nla_client_init(rdpNla* nla)
PromptPassword = FALSE;
}
}
#endif
if (PromptPassword)
@@ -611,6 +806,8 @@ static int nla_client_init(rdpNla* nla)
}
else
{
BOOL usePassword = TRUE;
if (settings->RedirectionPassword && (settings->RedirectionPasswordLength > 0))
{
if (sspi_SetAuthIdentityWithUnicodePassword(
@@ -619,40 +816,59 @@ static int nla_client_init(rdpNla* nla)
settings->RedirectionPasswordLength / sizeof(WCHAR) - 1) < 0)
return -1;
}
else
if (settings->RestrictedAdminModeRequired)
{
BOOL usePassword = TRUE;
if (settings->RestrictedAdminModeRequired)
{
if (settings->PasswordHash)
{
if (strlen(settings->PasswordHash) == 32)
{
if (sspi_SetAuthIdentity(nla->identity, settings->Username,
settings->Domain, settings->PasswordHash) < 0)
return -1;
/**
* Increase password hash length by LB_PASSWORD_MAX_LENGTH to obtain a
* length exceeding the maximum (LB_PASSWORD_MAX_LENGTH) and use it this for
* hash identification in WinPR.
*/
nla->identity->PasswordLength += LB_PASSWORD_MAX_LENGTH;
usePassword = FALSE;
}
}
}
if (usePassword)
if (settings->PasswordHash && strlen(settings->PasswordHash) == 32)
{
if (sspi_SetAuthIdentity(nla->identity, settings->Username, settings->Domain,
settings->Password) < 0)
settings->PasswordHash) < 0)
return -1;
/**
* Increase password hash length by LB_PASSWORD_MAX_LENGTH to obtain a
* length exceeding the maximum (LB_PASSWORD_MAX_LENGTH) and use it this for
* hash identification in WinPR.
*/
nla->identity->PasswordLength += LB_PASSWORD_MAX_LENGTH;
usePassword = FALSE;
}
}
if (usePassword)
{
if (sspi_SetAuthIdentity(nla->identity, settings->Username, settings->Domain,
settings->Password) < 0)
return -1;
}
}
return TRUE;
}
/**
* Initialize NTLM/Kerberos SSP authentication module (client).
* @param credssp
*/
static int nla_client_init(rdpNla* nla)
{
char* spn;
size_t length;
rdpTls* tls = NULL;
rdpSettings* settings = nla->settings;
nla_set_state(nla, NLA_STATE_INITIAL);
if (settings->RestrictedAdminModeRequired)
settings->DisableCredentialsDelegation = TRUE;
if (settings->SmartcardLogon && !nla_adjust_settings_from_smartcard(nla))
return -1;
if (!nla_client_setup_identity(nla))
return -1;
tls = transport_get_tls(nla->transport);
if (!tls)
@@ -689,7 +905,7 @@ static int nla_client_init(rdpNla* nla)
WLog_DBG(TAG, "%s %" PRIu32 " : packageName=%ls ; cbMaxToken=%d", __FUNCTION__, __LINE__,
nla->packageName, nla->cbMaxToken);
nla->status = nla->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME, SECPKG_CRED_OUTBOUND,
NULL, nla->identity, NULL, NULL,
NULL, nla->identityPtr, NULL, NULL,
&nla->credentials, &nla->expiration);
if (nla->status != SEC_E_OK)
@@ -892,7 +1108,6 @@ static int nla_client_recv_pub_key_auth(rdpNla* nla)
/* Send encrypted credentials */
nla->status = nla_encrypt_ts_credentials(nla);
if (nla->status != SEC_E_OK)
return -1;
@@ -1576,30 +1791,6 @@ fail:
return status;
}
static size_t nla_sizeof_ts_password_creds(rdpNla* nla)
{
size_t length = 0;
if (nla->identity)
{
length += ber_sizeof_sequence_octet_string(nla->identity->DomainLength * 2);
length += ber_sizeof_sequence_octet_string(nla->identity->UserLength * 2);
length += ber_sizeof_sequence_octet_string(nla->identity->PasswordLength * 2);
}
return length;
}
static size_t nla_sizeof_ts_credentials(rdpNla* nla)
{
size_t size = 0;
size += ber_sizeof_integer(1);
size += ber_sizeof_contextual_tag(ber_sizeof_integer(1));
size +=
ber_sizeof_sequence_octet_string(ber_sizeof_sequence(nla_sizeof_ts_password_creds(nla)));
return size;
}
BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s)
{
size_t length;
@@ -1691,29 +1882,6 @@ BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s)
return TRUE;
}
static size_t nla_write_ts_password_creds(rdpNla* nla, wStream* s)
{
size_t size = 0;
size_t innerSize = nla_sizeof_ts_password_creds(nla);
/* TSPasswordCreds (SEQUENCE) */
size += ber_write_sequence_tag(s, innerSize);
if (nla->identity)
{
/* [0] domainName (OCTET STRING) */
size += ber_write_sequence_octet_string(s, 0, (BYTE*)nla->identity->Domain,
nla->identity->DomainLength * 2);
/* [1] userName (OCTET STRING) */
size += ber_write_sequence_octet_string(s, 1, (BYTE*)nla->identity->User,
nla->identity->UserLength * 2);
/* [2] password (OCTET STRING) */
size += ber_write_sequence_octet_string(s, 2, (BYTE*)nla->identity->Password,
nla->identity->PasswordLength * 2);
}
return size;
}
static BOOL nla_read_ts_credentials(rdpNla* nla, SecBuffer* data, size_t offset)
{
wStream* s;
@@ -1748,23 +1916,6 @@ fail:
return ret;
}
static size_t nla_write_ts_credentials(rdpNla* nla, wStream* s)
{
size_t size = 0;
size_t passwordSize;
size_t innerSize = nla_sizeof_ts_credentials(nla);
/* TSCredentials (SEQUENCE) */
size += ber_write_sequence_tag(s, innerSize);
/* [0] credType (INTEGER) */
size += ber_write_contextual_tag(s, 0, ber_sizeof_integer(1), TRUE);
size += ber_write_integer(s, 1);
/* [1] credentials (OCTET STRING) */
passwordSize = ber_sizeof_sequence(nla_sizeof_ts_password_creds(nla));
size += ber_write_contextual_tag(s, 1, ber_sizeof_octet_string(passwordSize), TRUE);
size += ber_write_octet_string_tag(s, passwordSize);
size += nla_write_ts_password_creds(nla, s);
return size;
}
/**
* Encode TSCredentials structure.
@@ -1773,57 +1924,88 @@ static size_t nla_write_ts_credentials(rdpNla* nla, wStream* s)
static BOOL nla_encode_ts_credentials(rdpNla* nla)
{
wStream* credsContentStream;
wStream staticRetStream;
wStream* s;
size_t length;
UINT32 DomainLength = 0;
UINT32 UserLength = 0;
UINT32 PasswordLength = 0;
BOOL ret = FALSE;
if (nla->identity)
TSCredentials_t cr = { 0 };
rdpSettings* settings = nla->settings;
if (settings->SmartcardLogon)
{
/* TSPasswordCreds */
DomainLength = nla->identity->DomainLength;
UserLength = nla->identity->UserLength;
PasswordLength = nla->identity->PasswordLength;
TSSmartCardCreds_t smartcardCreds = { 0 };
TSCspDataDetail_t cspData = { 0 };
if (settings->SmartcardEmulation)
smartcardCreds.pin = settings->SmartcardPin;
if (!smartcardCreds.pin)
smartcardCreds.pin = settings->Pin ? settings->Pin : "";
/*smartcardCreds.userHint = settings->UserHint;
smartcardCreds.domainHint = settings->DomainHint;*/
smartcardCreds.cspData = &cspData;
cspData.keySpec = settings->KeySpec;
cspData.cspName = settings->CspName;
cspData.readerName = settings->ReaderName;
cspData.cardName = settings->CardName;
cspData.containerName = settings->ContainerName;
length = ber_sizeof_nla_TSSmartCardCreds(&smartcardCreds);
credsContentStream = Stream_New(NULL, length);
if (!credsContentStream)
return FALSE;
if (ber_write_nla_TSSmartCardCreds(credsContentStream, &smartcardCreds) == 0)
return FALSE;
cr.credType = 2;
}
else
{
TSPasswordCreds_t passCreds = { 0 };
if (!nla->settings->DisableCredentialsDelegation && nla->identity)
{
passCreds.userNameLen = nla->identity->UserLength * 2;
passCreds.userName = (BYTE*)nla->identity->User;
passCreds.domainNameLen = nla->identity->DomainLength * 2;
passCreds.domainName = (BYTE*)nla->identity->Domain;
passCreds.passwordLen = nla->identity->PasswordLength * 2;
passCreds.password = (BYTE*)nla->identity->Password;
}
length = ber_sizeof_nla_TSPasswordCreds(&passCreds);
credsContentStream = Stream_New(NULL, length);
if (!credsContentStream)
return FALSE;
ber_write_nla_TSPasswordCreds(credsContentStream, &passCreds);
cr.credType = 1;
}
if (nla->settings->DisableCredentialsDelegation && nla->identity)
{
/* TSPasswordCreds */
nla->identity->DomainLength = 0;
nla->identity->UserLength = 0;
nla->identity->PasswordLength = 0;
}
length = ber_sizeof_sequence(nla_sizeof_ts_credentials(nla));
cr.credentialsLen = length;
cr.credentials = Stream_Buffer(credsContentStream);
length = ber_sizeof_nla_TSCredentials(&cr);
if (!nla_sec_buffer_alloc(&nla->tsCredentials, length))
{
WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
return FALSE;
goto out;
}
s = Stream_New((BYTE*)nla->tsCredentials.pvBuffer, length);
s = Stream_StaticInit(&staticRetStream, (BYTE*)nla->tsCredentials.pvBuffer, length);
ber_write_nla_TSCredentials(s, &cr);
ret = TRUE;
if (!s)
{
sspi_SecBufferFree(&nla->tsCredentials);
WLog_ERR(TAG, "Stream_New failed!");
return FALSE;
}
nla_write_ts_credentials(nla, s);
if (nla->settings->DisableCredentialsDelegation && nla->identity)
{
/* TSPasswordCreds */
nla->identity->DomainLength = DomainLength;
nla->identity->UserLength = UserLength;
nla->identity->PasswordLength = PasswordLength;
}
Stream_Free(s, FALSE);
return TRUE;
printf("creds=%s\n", winpr_BinToHexString((BYTE*)nla->tsCredentials.pvBuffer, length, TRUE));
out:
Stream_Free(credsContentStream, TRUE);
return ret;
}
static SECURITY_STATUS nla_encrypt_ts_credentials(rdpNla* nla)
@@ -2289,6 +2471,7 @@ rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* setting
return NULL;
}
nla->identityPtr = nla->identity;
nla->instance = instance;
nla->settings = settings;
nla->server = settings->ServerMode;
@@ -2296,6 +2479,7 @@ rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* setting
nla->sendSeqNum = 0;
nla->recvSeqNum = 0;
nla->version = 6;
nla->identityWinPr.kerberosSettings = &nla->kerberosSettings;
SecInvalidateHandle(&nla->context);
if (settings->NtlmSamFile)

View File

@@ -391,7 +391,8 @@ rdpSettings* freerdp_settings_new(DWORD flags)
!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, 0) ||
!freerdp_settings_set_uint32(settings, FreeRDP_ChannelDefArraySize, 32) ||
!freerdp_settings_set_bool(settings, FreeRDP_CertificateUseKnownHosts, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, FALSE))
!freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, FALSE) ||
!freerdp_settings_set_uint32(settings, FreeRDP_KeySpec, AT_KEYEXCHANGE))
goto out_fail;
settings->ChannelDefArray = (CHANNEL_DEF*)calloc(

View File

@@ -0,0 +1,404 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Logging in with smartcards
*
* Copyright 2022 David Fort <contact@hardening-consulting.com>
*
* 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.
*/
#include <string.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/objects.h>
#include <winpr/error.h>
#include <winpr/ncrypt.h>
#include <winpr/string.h>
#include <winpr/wlog.h>
#include <winpr/smartcard.h>
#include <winpr/crypto.h>
#include <freerdp/log.h>
#include "smartcardlogon.h"
#define TAG FREERDP_TAG("smartcardlogon")
static BOOL getAtr(LPWSTR readerName, BYTE* atr, DWORD* atrLen)
{
WCHAR atrName[256];
DWORD cbLength;
DWORD dwShareMode = SCARD_SHARE_SHARED;
DWORD dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
SCARDHANDLE hCardHandle;
DWORD dwActiveProtocol = 0;
BOOL ret = FALSE;
LONG status = 0;
SCARDCONTEXT scContext;
status = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &scContext);
if (status != ERROR_SUCCESS || !scContext)
return FALSE;
status = SCardConnectW(scContext, readerName, dwShareMode, dwPreferredProtocols, &hCardHandle,
&dwActiveProtocol);
if (status != ERROR_SUCCESS)
goto out_connect;
*atrLen = 256;
status = SCardGetAttrib(hCardHandle, SCARD_ATTR_ATR_STRING, atr, atrLen);
if (status != ERROR_SUCCESS)
goto out_get_attrib;
cbLength = 256;
status = SCardListCardsW(scContext, atr, NULL, 0, atrName, &cbLength);
if (status != ERROR_SUCCESS)
goto out_listCards;
/* WLog_DBG(TAG, "ATR name: %ld -> %S\n", cbLength, atrName); */
ret = TRUE;
out_listCards:
out_get_attrib:
SCardDisconnect(scContext, SCARD_LEAVE_CARD);
out_connect:
SCardReleaseContext(scContext);
return ret;
}
void smartcardCert_Free(SmartcardCert* scCert)
{
free(scCert->reader);
crypto_cert_free(scCert->certificate);
free(scCert->pkinitArgs);
free(scCert->containerName);
free(scCert->upn);
free(scCert->userHint);
free(scCert->domainHint);
free(scCert->subject);
free(scCert->issuer);
ZeroMemory(scCert, sizeof(*scCert));
}
static BOOL treat_sc_cert(SmartcardCert* scCert)
{
scCert->upn = crypto_cert_get_upn(scCert->certificate->px509);
if (scCert->upn)
{
size_t userLen;
const char* atPos = strchr(scCert->upn, '@');
if (!atPos)
{
WLog_ERR(TAG, "invalid UPN, for key %s (no @)", scCert->containerName);
return FALSE;
}
userLen = (atPos - scCert->upn);
scCert->userHint = malloc(userLen + 1);
scCert->domainHint = strdup(atPos + 1);
if (!scCert->userHint || !scCert->domainHint)
{
WLog_ERR(TAG, "error allocating userHint or domainHint, for key %s",
scCert->containerName);
return FALSE;
}
memcpy(scCert->userHint, scCert->upn, userLen);
scCert->userHint[userLen] = 0;
}
scCert->subject = crypto_cert_subject(scCert->certificate->px509);
scCert->issuer = crypto_cert_issuer(scCert->certificate->px509);
return TRUE;
}
#ifndef _WIN32
static BOOL build_pkinit_args(rdpSettings* settings, SmartcardCert* scCert)
{
/* pkinit args only under windows
* PKCS11:module_name=opensc-pkcs11.so
*/
size_t sz = strlen("PKCS11:module_name=:slotid=XXXXX");
const char* pkModule = settings->Pkcs11Module ? settings->Pkcs11Module : "opensc-pkcs11.so";
sz += strlen(pkModule) + 1;
scCert->pkinitArgs = malloc(sz);
if (!scCert->pkinitArgs)
return FALSE;
snprintf(scCert->pkinitArgs, sz, "PKCS11:module_name=%s:slotid=%" PRIu16, pkModule,
(UINT16)scCert->slotId);
return TRUE;
}
#endif /* _WIN32 */
static BOOL smartcard_hw_enumerateCerts(rdpSettings* settings, LPCWSTR csp, const char* reader,
const char* userFilter, SmartcardCert* scCert, DWORD count,
DWORD* retCount)
{
BOOL ret = FALSE;
LPWSTR scope = NULL;
PVOID enumState = NULL;
NCRYPT_PROV_HANDLE provider;
NCryptKeyName* keyName = NULL;
SECURITY_STATUS status;
if (reader)
{
int res;
size_t readerSz = strlen(reader);
char* scopeStr = malloc(4 + readerSz + 1 + 1);
if (!scopeStr)
goto out;
snprintf(scopeStr, readerSz + 5, "\\\\.\\%s\\", reader);
res = ConvertToUnicode(CP_UTF8, 0, scopeStr, -1, &scope, 0);
free(scopeStr);
if (res <= 0)
goto out;
}
status = NCryptOpenStorageProvider(&provider, csp, 0);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to open provider");
goto out;
}
*retCount = 0;
while ((*retCount < count) && (status = NCryptEnumKeys(provider, scope, &keyName, &enumState,
NCRYPT_SILENT_FLAG)) == ERROR_SUCCESS)
{
NCRYPT_KEY_HANDLE phKey;
PBYTE certBytes = NULL;
DWORD cbOutput;
if (ConvertFromUnicode(CP_UTF8, 0, keyName->pszName, -1, &scCert->containerName, 0, NULL,
NULL) <= 0)
continue;
status = NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec,
keyName->dwFlags);
if (status != ERROR_SUCCESS)
{
smartcardCert_Free(scCert);
continue;
}
#ifndef _WIN32
status = NCryptGetProperty(phKey, NCRYPT_WINPR_SLOTID, (PBYTE)&scCert->slotId, 4, &cbOutput,
NCRYPT_SILENT_FLAG);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve slotId for key %s", scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
#endif /* _WIN32 */
/* ====== retrieve key's reader ====== */
status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, NULL, 0, &cbOutput,
NCRYPT_SILENT_FLAG);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve reader's name length for key %s",
scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
scCert->reader = calloc(1, cbOutput + 2);
if (!scCert->reader)
{
WLog_ERR(TAG, "unable to allocate reader's name for key %s", scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)scCert->reader,
cbOutput + 2, &cbOutput, NCRYPT_SILENT_FLAG);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve reader's name for key %s", scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
if (!getAtr(scCert->reader, scCert->atr, &scCert->atrLength))
{
WLog_ERR(TAG, "unable to retrieve card ATR for key %s", scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
/* ========= retrieve the certificate ===============*/
status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, NULL, 0, &cbOutput,
NCRYPT_SILENT_FLAG);
if (status != ERROR_SUCCESS)
{
/* can happen that key don't have certificates */
smartcardCert_Free(scCert);
goto endofloop;
}
certBytes = calloc(1, cbOutput);
if (!certBytes)
{
WLog_ERR(TAG, "unable to allocate %d certBytes for key %s", cbOutput,
scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, certBytes, cbOutput,
&cbOutput, NCRYPT_SILENT_FLAG);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve certificate for key %s", scCert->containerName);
free(certBytes);
smartcardCert_Free(scCert);
goto endofloop;
}
if (!winpr_Digest(WINPR_MD_SHA1, certBytes, cbOutput, scCert->sha1Hash,
sizeof(scCert->sha1Hash)))
{
WLog_ERR(TAG, "unable to compute certificate sha1 for key %s", scCert->containerName);
free(certBytes);
smartcardCert_Free(scCert);
goto endofloop;
}
scCert->certificate = crypto_cert_read(certBytes, cbOutput);
free(certBytes);
if (!scCert->certificate)
{
WLog_ERR(TAG, "unable to parse X509 certificate for key %s", scCert->containerName);
smartcardCert_Free(scCert);
goto endofloop;
}
if (!treat_sc_cert(scCert))
{
smartcardCert_Free(scCert);
goto endofloop;
}
if (userFilter && scCert->userHint && strcmp(scCert->userHint, userFilter) != 0)
{
smartcardCert_Free(scCert);
goto endofloop;
}
#ifndef _WIN32
if (!build_pkinit_args(settings, scCert))
{
WLog_ERR(TAG, "error build pkinit args");
smartcardCert_Free(scCert);
goto endofloop;
}
#endif
++*retCount;
scCert++;
endofloop:
NCryptFreeObject((NCRYPT_HANDLE)phKey);
}
ret = TRUE;
NCryptFreeObject((NCRYPT_HANDLE)provider);
out:
free(scope);
return ret;
}
BOOL smartcard_sw_enumerateCerts(rdpSettings* settings, SmartcardCert* scCert, DWORD count,
DWORD* retCount)
{
size_t sz;
if (count < 1)
return FALSE;
if (!settings->SmartcardCertificateFile || !settings->SmartcardPrivateKeyFile)
{
WLog_ERR(TAG, "missing smartcard emulation cert or key");
return FALSE;
}
/* compute PKINIT args FILE:<cert file>,<key file> */
sz = strlen("FILE:") + strlen(settings->SmartcardCertificateFile) + 1 +
strlen(settings->SmartcardPrivateKeyFile) + 1;
scCert->pkinitArgs = malloc(sz);
snprintf(scCert->pkinitArgs, sz, "FILE:%s,%s", settings->SmartcardCertificateFile,
settings->SmartcardPrivateKeyFile);
scCert->certificate = crypto_cert_pem_read(settings->SmartcardCertificate);
if (!scCert->certificate)
{
WLog_ERR(TAG, "unable to read smartcard certificate");
goto out_error;
}
if (!treat_sc_cert(scCert))
{
WLog_ERR(TAG, "unable to treat smartcard certificate");
goto out_error;
}
if (ConvertToUnicode(CP_UTF8, 0, "FreeRDP Emulator", -1, &scCert->reader, 0) < 0)
goto out_error;
scCert->containerName = strdup("Private Key 00");
if (!scCert->containerName)
goto out_error;
*retCount = 1;
return TRUE;
out_error:
smartcardCert_Free(scCert);
return FALSE;
}
BOOL smartcard_enumerateCerts(rdpSettings* settings, SmartcardCert* scCert, DWORD count,
DWORD* retCount)
{
BOOL ret;
LPWSTR csp;
const char* asciiCsp = settings->CspName ? settings->CspName : MS_SCARD_PROV_A;
if (settings->SmartcardEmulation)
return smartcard_sw_enumerateCerts(settings, scCert, count, retCount);
if (ConvertToUnicode(CP_UTF8, 0, asciiCsp, -1, &csp, 0) <= 0)
{
WLog_ERR(TAG, "error while converting CSP to WCHAR");
return FALSE;
}
ret = smartcard_hw_enumerateCerts(settings, csp, settings->ReaderName, settings->Username,
scCert, count, retCount);
free(csp);
return ret;
}

View File

@@ -0,0 +1,47 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Logging in with smartcards
*
* Copyright 2022 David Fort <contact@hardening-consulting.com>
*
* 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.
*/
#ifndef LIBFREERDP_CORE_SMARTCARDLOGON_H
#define LIBFREERDP_CORE_SMARTCARDLOGON_H
#include <freerdp/settings.h>
#include <freerdp/crypto/crypto.h>
typedef struct
{
LPWSTR reader;
CryptoCert certificate;
char* pkinitArgs;
UINT32 slotId;
char* containerName;
char* upn;
char* userHint;
char* domainHint;
char* subject;
char* issuer;
BYTE atr[256];
DWORD atrLength;
BYTE sha1Hash[20];
} SmartcardCert;
void smartcardCert_Free(SmartcardCert* scCert);
BOOL smartcard_enumerateCerts(rdpSettings* settings, SmartcardCert* scCert, DWORD count,
DWORD* retCount);
#endif /* LIBFREERDP_CORE_SMARTCARDLOGON_H */

View File

@@ -89,6 +89,7 @@ static const size_t bool_list_indices[] = {
FreeRDP_IgnoreCertificate,
FreeRDP_JpegCodec,
FreeRDP_ListMonitors,
FreeRDP_ListSmartcards,
FreeRDP_LocalConnection,
FreeRDP_LogonErrors,
FreeRDP_LogonNotify,
@@ -232,6 +233,7 @@ static const size_t uint32_list_indices[] = {
FreeRDP_GlyphSupportLevel,
FreeRDP_JpegCodecId,
FreeRDP_JpegQuality,
FreeRDP_KeySpec,
FreeRDP_KeyboardCodePage,
FreeRDP_KeyboardFunctionKey,
FreeRDP_KeyboardHook,
@@ -322,6 +324,7 @@ static const size_t string_list_indices[] = {
FreeRDP_AlternateShell,
FreeRDP_AssistanceFile,
FreeRDP_AuthenticationServiceClass,
FreeRDP_CardName,
FreeRDP_CertificateAcceptedFingerprints,
FreeRDP_CertificateContent,
FreeRDP_CertificateFile,
@@ -333,6 +336,8 @@ static const size_t string_list_indices[] = {
FreeRDP_ComputerName,
FreeRDP_ConfigPath,
FreeRDP_ConnectionFile,
FreeRDP_ContainerName,
FreeRDP_CspName,
FreeRDP_CurrentPath,
FreeRDP_Domain,
FreeRDP_DrivesToRedirect,
@@ -347,11 +352,17 @@ static const size_t string_list_indices[] = {
FreeRDP_HomePath,
FreeRDP_ImeFileName,
FreeRDP_KerberosKdc,
FreeRDP_KerberosLifeTime,
FreeRDP_KerberosRealm,
FreeRDP_KerberosRenewableLifeTime,
FreeRDP_KerberosStartTime,
FreeRDP_KeyboardRemappingList,
FreeRDP_NtlmSamFile,
FreeRDP_Password,
FreeRDP_PasswordHash,
FreeRDP_Pin,
FreeRDP_Pkcs11Module,
FreeRDP_PkinitAnchors,
FreeRDP_PlayRemoteFxFile,
FreeRDP_PreconnectionBlob,
FreeRDP_PrivateKeyContent,
@@ -362,6 +373,7 @@ static const size_t string_list_indices[] = {
FreeRDP_RDP2TCPArgs,
FreeRDP_RdpKeyContent,
FreeRDP_RdpKeyFile,
FreeRDP_ReaderName,
FreeRDP_RedirectionAcceptedCert,
FreeRDP_RedirectionDomain,
FreeRDP_RedirectionTargetFQDN,
@@ -381,8 +393,10 @@ static const size_t string_list_indices[] = {
FreeRDP_ServerHostname,
FreeRDP_ShellWorkingDirectory,
FreeRDP_SmartcardCertificate,
FreeRDP_SmartcardCertificateFile,
FreeRDP_SmartcardPin,
FreeRDP_SmartcardPrivateKey,
FreeRDP_SmartcardPrivateKeyFile,
FreeRDP_TargetNetAddress,
FreeRDP_TransportDumpFile,
FreeRDP_Username,

View File

@@ -41,6 +41,23 @@ CryptoCert crypto_cert_read(const BYTE* data, UINT32 length)
return cert;
}
CryptoCert crypto_cert_pem_read(const char* data)
{
CryptoCert cert = malloc(sizeof(*cert));
if (!cert)
return NULL;
cert->px509 = crypto_cert_from_pem(data, strlen(data), FALSE);
if (!cert->px509)
{
free(cert);
return NULL;
}
return cert;
}
void crypto_cert_free(CryptoCert cert)
{
if (cert == NULL)

View File

@@ -28,6 +28,7 @@ set(${MODULE_PREFIX}_SRCS
smartcard_operations.c
smartcard_pack.c
smartcard_call.c
smartcard_cli.c
stopwatch.c)
freerdp_module_add(${${MODULE_PREFIX}_SRCS})

View File

@@ -0,0 +1,50 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Smartcard client functions
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* 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.
*/
#include <freerdp/utils/smartcard_cli.h>
#include "../core/smartcardlogon.h"
BOOL freerdp_smartcard_list(rdpSettings* settings)
{
SmartcardCert certs[64] = { 0 };
DWORD i, count;
if (!smartcard_enumerateCerts(settings, certs, 64, &count))
return FALSE;
for (i = 0; i < count; i++)
{
char readerName[256] = { 0 };
printf("%d: %s\n", i, certs[i].subject);
if (WideCharToMultiByte(CP_UTF8, 0, certs[i].reader, -1, readerName, sizeof(readerName),
NULL, NULL) > 0)
printf("\t* reader: %s\n", readerName);
#ifndef _WIN32
printf("\t* slotId: %" PRIu32 "\n", certs[i].slotId);
printf("\t* pkinitArgs: %s\n", certs[i].pkinitArgs);
#endif
printf("\t* containerName: %s\n", certs[i].containerName);
if (certs[i].upn)
printf("\t* UPN: %s\n", certs[i].upn);
smartcardCert_Free(&certs[i]);
}
return TRUE;
}

View File

@@ -0,0 +1,57 @@
/**
* WinPR: Windows Portable Runtime
* Windows credentials
*
* Copyright 2022 David Fort <contact@hardening-consulting.com>
*
* 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.
*/
#ifndef WINPR_CRED_H_
#define WINPR_CRED_H_
#ifdef _WIN32
#include <wincred.h>
#else
#define CERT_HASH_LENGTH 20
typedef enum _CRED_MARSHAL_TYPE
{
CertCredential,
UsernameTargetCredential,
BinaryBlobCredential,
UsernameForPackedCredentials,
BinaryBlobForSystem
} CRED_MARSHAL_TYPE,
*PCRED_MARSHAL_TYPE;
typedef struct _CERT_CREDENTIAL_INFO
{
ULONG cbSize;
UCHAR rgbHashOfCert[CERT_HASH_LENGTH];
} CERT_CREDENTIAL_INFO, *PCERT_CREDENTIAL_INFO;
BOOL CredMarshalCredentialA(CRED_MARSHAL_TYPE CredType, PVOID Credential,
LPSTR* MarshaledCredential);
BOOL CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType, PVOID Credential,
LPWSTR* MarshaledCredential);
#ifdef UNICODE
#define CredMarshalCredential CredMarshalCredentialW
#else
#define CredMarshalCredential CredMarshalCredentialA
#endif
#endif /* _WIN32 */
#endif /* WINPR_CRED_H_ */

View File

@@ -157,23 +157,27 @@ extern "C"
{
#endif
SECURITY_STATUS NCryptEnumStorageProviders(DWORD* wProviderCount,
NCryptProviderName** ppProviderList, DWORD dwFlags);
WINPR_API SECURITY_STATUS NCryptEnumStorageProviders(DWORD* wProviderCount,
NCryptProviderName** ppProviderList,
DWORD dwFlags);
SECURITY_STATUS NCryptOpenStorageProvider(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags);
WINPR_API SECURITY_STATUS NCryptOpenStorageProvider(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags);
SECURITY_STATUS NCryptEnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
NCryptKeyName** ppKeyName, PVOID* ppEnumState, DWORD dwFlags);
WINPR_API SECURITY_STATUS NCryptEnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
NCryptKeyName** ppKeyName, PVOID* ppEnumState,
DWORD dwFlags);
SECURITY_STATUS NCryptOpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags);
WINPR_API SECURITY_STATUS NCryptOpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
LPCWSTR pszKeyName, DWORD dwLegacyKeySpec,
DWORD dwFlags);
SECURITY_STATUS NCryptGetProperty(NCRYPT_HANDLE hObject, LPCWSTR pszProperty, PBYTE pbOutput,
DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags);
WINPR_API SECURITY_STATUS NCryptGetProperty(NCRYPT_HANDLE hObject, LPCWSTR pszProperty,
PBYTE pbOutput, DWORD cbOutput, DWORD* pcbResult,
DWORD dwFlags);
SECURITY_STATUS NCryptFreeObject(NCRYPT_HANDLE hObject);
SECURITY_STATUS NCryptFreeBuffer(PVOID pvInput);
WINPR_API SECURITY_STATUS NCryptFreeObject(NCRYPT_HANDLE hObject);
WINPR_API SECURITY_STATUS NCryptFreeBuffer(PVOID pvInput);
#ifdef __cplusplus
}

View File

@@ -34,13 +34,13 @@
#include <sspi.h>
#include <security.h>
#endif
#endif /* _WIN32 */
#if !defined(_WIN32) || defined(_UWP)
#ifndef SEC_ENTRY
#define SEC_ENTRY
#endif
#endif /* SEC_ENTRY */
typedef CHAR SEC_CHAR;
typedef WCHAR SEC_WCHAR;
@@ -62,7 +62,7 @@ typedef SECURITY_INTEGER* PTimeStamp;
#ifndef __SECSTATUS_DEFINED__
typedef LONG SECURITY_STATUS;
#define __SECSTATUS_DEFINED__
#endif
#endif /* __SECSTATUS_DEFINED__ */
#if defined(__clang__)
#pragma clang diagnostic pop
@@ -96,9 +96,9 @@ typedef SecPkgInfoW* PSecPkgInfoW;
#else
#define SecPkgInfo SecPkgInfoA
#define PSecPkgInfo PSecPkgInfoA
#endif
#endif /* UNICODE */
#endif
#endif /* !defined(_WIN32) || defined(_UWP) */
#define NTLM_SSP_NAME _T("NTLM")
#define KERBEROS_SSP_NAME _T("Kerberos")
@@ -217,7 +217,7 @@ typedef SecPkgInfoW* PSecPkgInfoW;
#define SEC_I_SIGNATURE_NEEDED (SECURITY_STATUS)0x0009035CL
#define SEC_I_NO_RENEGOTIATION (SECURITY_STATUS)0x00090360L
#endif
#endif /* _WINERROR_ */
/* ============== some definitions missing in mingw ========================*/
#ifndef SEC_E_INVALID_PARAMETER
@@ -482,7 +482,7 @@ typedef SecPkgCredentials_NamesW* PSecPkgCredentials_NamesW;
#define PSecPkgCredentials_Names PSecPkgCredentials_NamesA
#endif
#endif
#endif /* !defined(_WIN32) || defined(_UWP) */
#if !defined(_WIN32) || defined(_UWP)
#if !defined(__MINGW32__)
@@ -601,6 +601,17 @@ typedef struct
#define SEC_WINNT_AUTH_IDENTITY_ANSI 0x1
#define SEC_WINNT_AUTH_IDENTITY_UNICODE 0x2
typedef struct
{
char* armorCache;
char* pkinitX509Anchors;
char* pkinitX509Identity;
BOOL withPac;
INT32 startTime;
INT32 lifeTime;
BYTE certSha1[20];
} SEC_WINPR_KERBEROS_SETTINGS;
#if !defined(_WIN32) || defined(_UWP)
#if defined(__clang__)
@@ -649,6 +660,42 @@ typedef struct
#endif /* _AUTH_IDENTITY_DEFINED */
#ifndef SEC_WINNT_AUTH_IDENTITY_VERSION
#define SEC_WINNT_AUTH_IDENTITY_VERSION 0x200
typedef struct _SEC_WINNT_AUTH_IDENTITY_EXW
{
UINT32 Version;
UINT32 Length;
UINT16* User;
UINT32 UserLength;
UINT16* Domain;
UINT32 DomainLength;
UINT16* Password;
UINT32 PasswordLength;
UINT32 Flags;
BYTE* PackageList;
UINT32 PackageListLength;
} SEC_WINNT_AUTH_IDENTITY_EXW, *PSEC_WINNT_AUTH_IDENTITY_EXW;
typedef struct _SEC_WINNT_AUTH_IDENTITY_EXA
{
UINT32 Version;
UINT32 Length;
BYTE* User;
UINT32 UserLength;
BYTE* Domain;
UINT32 DomainLength;
BYTE* Password;
UINT32 PasswordLength;
UINT32 Flags;
BYTE* PackageList;
UINT32 PackageListLength;
} SEC_WINNT_AUTH_IDENTITY_EXA, *PSEC_WINNT_AUTH_IDENTITY_EXA;
#endif /* SEC_WINNT_AUTH_IDENTITY_VERSION */
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
@@ -672,7 +719,19 @@ typedef CtxtHandle* PCtxtHandle;
((((PSecHandle)(x))->dwLower != ((ULONG_PTR)((INT_PTR)-1))) && \
(((PSecHandle)(x))->dwUpper != ((ULONG_PTR)((INT_PTR)-1))))
#endif
#endif /* !defined(_WIN32) || defined(_UWP) */
typedef struct _SEC_WINNT_AUTH_IDENTITY_WINPRA
{
SEC_WINNT_AUTH_IDENTITY_EXA identityEx;
SEC_WINPR_KERBEROS_SETTINGS* kerberosSettings;
} SEC_WINNT_AUTH_IDENTITY_WINPRA, *PSEC_WINNT_AUTH_IDENTITY_WINPRA;
typedef struct _SEC_WINNT_AUTH_IDENTITY_WINPRW
{
SEC_WINNT_AUTH_IDENTITY_EXW identityEx;
SEC_WINPR_KERBEROS_SETTINGS* kerberosSettings;
} SEC_WINNT_AUTH_IDENTITY_WINPRW, *PSEC_WINNT_AUTH_IDENTITY_WINPRW;
#define SECBUFFER_VERSION 0

View File

@@ -43,6 +43,10 @@ winpr_module_add(
ncrypt_pkcs11.c
)
if (WIN32)
winpr_library_add_public(ncrypt)
endif()
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -84,11 +84,13 @@ SECURITY_STATUS winpr_NCryptDefault_dtor(NCRYPT_HANDLE handle)
SECURITY_STATUS NCryptEnumStorageProviders(DWORD* wProviderCount,
NCryptProviderName** ppProviderList, DWORD dwFlags)
{
static const WCHAR emptyComment[] = { 0 };
NCryptProviderName* ret;
size_t stringAllocSize = 0;
#ifdef WITH_PKCS11
LPWSTR strPtr;
static const WCHAR emptyComment[] = { 0 };
size_t copyAmount;
#endif
*wProviderCount = 0;
*ppProviderList = NULL;
@@ -106,9 +108,10 @@ SECURITY_STATUS NCryptEnumStorageProviders(DWORD* wProviderCount,
if (!ret)
return NTE_NO_MEMORY;
strPtr = (LPWSTR)(ret + *wProviderCount);
#ifdef WITH_PKCS11
strPtr = (LPWSTR)(ret + *wProviderCount);
ret->pszName = strPtr;
copyAmount = (_wcslen(MS_SCARD_PROV) + 1) * 2;
memcpy(strPtr, MS_SCARD_PROV, copyAmount);

View File

@@ -26,6 +26,8 @@
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <winpr/assert.h>
#include <winpr/crt.h>
@@ -231,7 +233,26 @@ static int kerberos_SetContextServicePrincipalNameA(KRB_CONTEXT* context,
}
#ifdef WITH_GSSAPI
static krb5_error_code acquire_cred(krb5_context ctx, krb5_principal client, const char* password)
static krb5_error_code krb5_prompter(krb5_context context, void* data, const char* name,
const char* banner, int num_prompts, krb5_prompt prompts[])
{
int i;
krb5_prompt_type* ptypes = krb5_get_prompt_types(context);
for (i = 0; i < num_prompts; i++)
{
if (ptypes && ptypes[i] == KRB5_PROMPT_TYPE_PREAUTH)
{
prompts[i].reply->data = strdup((const char*)data);
prompts[i].reply->length = strlen((const char*)data);
}
}
return 0;
}
static krb5_error_code acquire_cred(krb5_context ctx, SEC_WINPR_KERBEROS_SETTINGS* optionsBlock,
krb5_principal client, const char* password)
{
krb5_error_code ret;
krb5_creds creds;
@@ -264,6 +285,21 @@ static krb5_error_code acquire_cred(krb5_context ctx, krb5_principal client, con
/* Set default options */
krb5_get_init_creds_opt_set_forwardable(options, 0);
krb5_get_init_creds_opt_set_proxiable(options, 0);
if (optionsBlock && optionsBlock->withPac)
krb5_get_init_creds_opt_set_pac_request(ctx, options, TRUE);
if (optionsBlock && optionsBlock->armorCache)
krb5_get_init_creds_opt_set_fast_ccache_name(ctx, options, optionsBlock->armorCache);
if (optionsBlock && optionsBlock->pkinitX509Identity)
krb5_get_init_creds_opt_set_pa(ctx, options, "X509_user_identity",
optionsBlock->pkinitX509Identity);
if (optionsBlock && optionsBlock->pkinitX509Anchors)
krb5_get_init_creds_opt_set_pa(ctx, options, "X509_anchors",
optionsBlock->pkinitX509Anchors);
#ifdef WITH_GSSAPI_MIT
/* for MIT we specify ccache output using an option */
@@ -275,7 +311,8 @@ static krb5_error_code acquire_cred(krb5_context ctx, krb5_principal client, con
#endif
if ((ret = krb5_init_creds_init(ctx, client, NULL, NULL, starttime, options, &init_ctx)))
if ((ret = krb5_init_creds_init(ctx, client, krb5_prompter, (void*)password, starttime, options,
&init_ctx)))
{
WLog_ERR(TAG, "error krb5_init_creds_init failed");
goto cleanup;
@@ -332,7 +369,8 @@ cleanup:
return ret;
}
static int init_creds(LPCWSTR username, size_t username_len, LPCWSTR password, size_t password_len)
static int init_creds(SEC_WINPR_KERBEROS_SETTINGS* options, LPCWSTR username, size_t username_len,
LPCWSTR domain, size_t domain_len, LPCWSTR password, size_t password_len)
{
krb5_error_code ret = 0;
krb5_context ctx = NULL;
@@ -347,6 +385,8 @@ static int init_creds(LPCWSTR username, size_t username_len, LPCWSTR password, s
size_t lrealm_len = 0;
size_t lusername_len = 0;
int status = 0;
BOOL isDefaultRealm = FALSE;
status = ConvertFromUnicode(CP_UTF8, 0, username, username_len, &lusername, 0, NULL, NULL);
if (status <= 0)
@@ -356,7 +396,6 @@ static int init_creds(LPCWSTR username, size_t username_len, LPCWSTR password, s
}
status = ConvertFromUnicode(CP_UTF8, 0, password, password_len, &lpassword, 0, NULL, NULL);
if (status <= 0)
{
WLog_ERR(TAG, "Failed to convert password");
@@ -372,12 +411,29 @@ static int init_creds(LPCWSTR username, size_t username_len, LPCWSTR password, s
goto cleanup;
}
ret = krb5_get_default_realm(ctx, &lrealm);
if (ret)
if (domain && domain_len)
{
WLog_WARN(TAG, "could not get Kerberos default realm");
goto cleanup;
char* tmp;
if (ConvertFromUnicode(CP_UTF8, 0, domain, domain_len, &lrealm, 0, NULL, NULL) <= 0)
{
WLog_ERR(TAG, "error: converting domain");
}
/* convert to upper case */
for (tmp = lrealm; *tmp; tmp++)
*tmp = toupper(*tmp);
isDefaultRealm = FALSE;
}
else
{
ret = krb5_get_default_realm(ctx, &lrealm);
if (ret)
{
WLog_WARN(TAG, "could not get Kerberos default realm");
goto cleanup;
}
isDefaultRealm = TRUE;
}
lrealm_len = strlen(lrealm);
@@ -411,7 +467,7 @@ static int init_creds(LPCWSTR username, size_t username_len, LPCWSTR password, s
goto cleanup;
}
ret = acquire_cred(ctx, principal, lpassword);
ret = acquire_cred(ctx, options, principal, lpassword);
if (ret)
{
@@ -427,7 +483,12 @@ cleanup:
free(krb_name);
if (lrealm)
krb5_free_default_realm(ctx, lrealm);
{
if (isDefaultRealm)
krb5_free_default_realm(ctx, lrealm);
else
free(lrealm);
}
if (principal)
krb5_free_principal(ctx, principal);
@@ -497,10 +558,11 @@ static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(
* If we use smartcard-logon, the credentials have already
* been acquired by pkinit process. If not, returned error previously.
*/
if (init_creds(context->credentials->identity.User,
context->credentials->identity.UserLength,
context->credentials->identity.Password,
context->credentials->identity.PasswordLength))
SSPI_CREDENTIALS* credentials = context->credentials;
if (init_creds(credentials->kerbSettings, credentials->identity.User,
credentials->identity.UserLength, credentials->identity.Domain,
credentials->identity.DomainLength, credentials->identity.Password,
credentials->identity.PasswordLength))
return SEC_E_NO_CREDENTIALS;
WLog_INFO(TAG, "Authenticated to Kerberos v5 via login/password");

View File

@@ -486,7 +486,6 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleW(
PTimeStamp ptsExpiry)
{
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
(fCredentialUse != SECPKG_CRED_BOTH))
@@ -495,17 +494,50 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleW(
}
credentials = sspi_CredentialsNew();
if (!credentials)
return SEC_E_INTERNAL_ERROR;
credentials->fCredentialUse = fCredentialUse;
credentials->pGetKeyFn = pGetKeyFn;
credentials->pvGetKeyArgument = pvGetKeyArgument;
identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
if (identity)
sspi_CopyAuthIdentity(&(credentials->identity), identity);
if (pAuthData)
{
SEC_WINNT_AUTH_IDENTITY_EXW* identityEx = (SEC_WINNT_AUTH_IDENTITY_EXW*)pAuthData;
BOOL treated = FALSE;
SEC_WINNT_AUTH_IDENTITY srcIdentity;
if (identityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
{
if (identityEx->Length >= sizeof(*identityEx))
{
srcIdentity.User = (UINT16*)identityEx->User;
srcIdentity.UserLength = identityEx->UserLength;
srcIdentity.Domain = (UINT16*)identityEx->Domain;
srcIdentity.DomainLength = identityEx->DomainLength;
srcIdentity.Password = (UINT16*)identityEx->Password;
srcIdentity.PasswordLength = identityEx->PasswordLength;
srcIdentity.Flags = identityEx->Flags;
if (!sspi_CopyAuthIdentity(&credentials->identity, &srcIdentity))
return SEC_E_INSUFFICIENT_MEMORY;
if (identityEx->Length == sizeof(SEC_WINNT_AUTH_IDENTITY_WINPRA))
{
SEC_WINNT_AUTH_IDENTITY_WINPRW* identityWinpr =
(SEC_WINNT_AUTH_IDENTITY_WINPRW*)pAuthData;
credentials->kerbSettings = identityWinpr->kerberosSettings;
}
treated = TRUE;
}
}
if (!treated)
{
SEC_WINNT_AUTH_IDENTITY* identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
sspi_CopyAuthIdentity(&(credentials->identity), identity);
}
}
sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*)NEGO_SSP_NAME);
@@ -518,7 +550,6 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleA(
PTimeStamp ptsExpiry)
{
SSPI_CREDENTIALS* credentials;
SEC_WINNT_AUTH_IDENTITY* identity;
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
(fCredentialUse != SECPKG_CRED_BOTH))
@@ -534,10 +565,44 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleA(
credentials->fCredentialUse = fCredentialUse;
credentials->pGetKeyFn = pGetKeyFn;
credentials->pvGetKeyArgument = pvGetKeyArgument;
identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
if (identity)
sspi_CopyAuthIdentity(&(credentials->identity), identity);
if (pAuthData)
{
SEC_WINNT_AUTH_IDENTITY_EXA* identityEx = (SEC_WINNT_AUTH_IDENTITY_EXA*)pAuthData;
BOOL treated = FALSE;
SEC_WINNT_AUTH_IDENTITY srcIdentity;
if (identityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
{
if (identityEx->Length >= sizeof(*identityEx))
{
srcIdentity.User = (UINT16*)identityEx->User;
srcIdentity.UserLength = identityEx->UserLength;
srcIdentity.Domain = (UINT16*)identityEx->Domain;
srcIdentity.DomainLength = identityEx->DomainLength;
srcIdentity.Password = (UINT16*)identityEx->Password;
srcIdentity.PasswordLength = identityEx->PasswordLength;
srcIdentity.Flags = identityEx->Flags;
if (!sspi_CopyAuthIdentity(&credentials->identity, &srcIdentity))
return SEC_E_INSUFFICIENT_MEMORY;
if (identityEx->Length == sizeof(SEC_WINNT_AUTH_IDENTITY_WINPRA))
{
SEC_WINNT_AUTH_IDENTITY_WINPRA* identityWinpr =
(SEC_WINNT_AUTH_IDENTITY_WINPRA*)pAuthData;
credentials->kerbSettings = identityWinpr->kerberosSettings;
}
treated = TRUE;
}
}
if (!treated)
{
SEC_WINNT_AUTH_IDENTITY* identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
sspi_CopyAuthIdentity(&(credentials->identity), identity);
}
}
sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
sspi_SecureHandleSetUpperPointer(phCredential, (void*)NEGO_SSP_NAME);

View File

@@ -28,14 +28,16 @@
#define SSPI_CREDENTIALS_HASH_LENGTH_OFFSET 512
typedef struct
struct _SSPI_CREDENTIALS
{
DWORD flags;
ULONG fCredentialUse;
SEC_GET_KEY_FN pGetKeyFn;
void* pvGetKeyArgument;
SEC_WINNT_AUTH_IDENTITY identity;
} SSPI_CREDENTIALS;
SEC_WINPR_KERBEROS_SETTINGS* kerbSettings;
};
typedef struct _SSPI_CREDENTIALS SSPI_CREDENTIALS;
SSPI_CREDENTIALS* sspi_CredentialsNew(void);
void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials);