mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2025-06-03 00:00:20 +00:00
server-side kerberos (and some fixes)
This commit is contained in:
parent
8d9f990124
commit
eeece1a027
@ -680,6 +680,7 @@ typedef struct
|
||||
#define FreeRDP_KerberosRenewableLifeTime (1348)
|
||||
#define FreeRDP_KerberosCache (1349)
|
||||
#define FreeRDP_KerberosArmor (1350)
|
||||
#define FreeRDP_KerberosKeytab (1351)
|
||||
#define FreeRDP_IgnoreCertificate (1408)
|
||||
#define FreeRDP_CertificateName (1409)
|
||||
#define FreeRDP_CertificateFile (1410)
|
||||
@ -1186,7 +1187,8 @@ struct rdp_settings
|
||||
ALIGN64 char* KerberosRenewableLifeTime; /* 1348 */
|
||||
ALIGN64 char* KerberosCache; /* 1349 */
|
||||
ALIGN64 char* KerberosArmor; /* 1350 */
|
||||
UINT64 padding1408[1408 - 1351]; /* 1351 */
|
||||
ALIGN64 char* KerberosKeytab; /* 1351 */
|
||||
UINT64 padding1408[1408 - 1352]; /* 1352 */
|
||||
|
||||
/* Server Certificate */
|
||||
ALIGN64 BOOL IgnoreCertificate; /* 1408 */
|
||||
|
@ -2454,6 +2454,9 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id)
|
||||
case FreeRDP_KerberosKdc:
|
||||
return settings->KerberosKdc;
|
||||
|
||||
case FreeRDP_KerberosKeytab:
|
||||
return settings->KerberosKeytab;
|
||||
|
||||
case FreeRDP_KerberosLifeTime:
|
||||
return settings->KerberosLifeTime;
|
||||
|
||||
@ -2718,6 +2721,9 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id)
|
||||
case FreeRDP_KerberosKdc:
|
||||
return settings->KerberosKdc;
|
||||
|
||||
case FreeRDP_KerberosKeytab:
|
||||
return settings->KerberosKeytab;
|
||||
|
||||
case FreeRDP_KerberosLifeTime:
|
||||
return settings->KerberosLifeTime;
|
||||
|
||||
@ -2992,6 +2998,9 @@ 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_KerberosKeytab:
|
||||
return update_string(&settings->KerberosKeytab, cnv.cc, len, cleanup);
|
||||
|
||||
case FreeRDP_KerberosLifeTime:
|
||||
return update_string(&settings->KerberosLifeTime, cnv.cc, len, cleanup);
|
||||
|
||||
|
@ -347,6 +347,7 @@ static const struct settings_str_entry settings_map[] = {
|
||||
{ FreeRDP_KerberosArmor, 7, "FreeRDP_KerberosArmor" },
|
||||
{ FreeRDP_KerberosCache, 7, "FreeRDP_KerberosCache" },
|
||||
{ FreeRDP_KerberosKdc, 7, "FreeRDP_KerberosKdc" },
|
||||
{ FreeRDP_KerberosKeytab, 7, "FreeRDP_KerberosKeytab" },
|
||||
{ FreeRDP_KerberosLifeTime, 7, "FreeRDP_KerberosLifeTime" },
|
||||
{ FreeRDP_KerberosRealm, 7, "FreeRDP_KerberosRealm" },
|
||||
{ FreeRDP_KerberosRenewableLifeTime, 7, "FreeRDP_KerberosRenewableLifeTime" },
|
||||
|
@ -943,6 +943,16 @@ static BOOL nla_setup_kerberos(rdpNla* nla)
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->KerberosKeytab)
|
||||
{
|
||||
kerbSettings->keytab = _strdup(settings->KerberosKeytab);
|
||||
if (!kerbSettings->keytab)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to copy keytab name");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->KerberosArmor)
|
||||
{
|
||||
kerbSettings->armorCache = _strdup(settings->KerberosArmor);
|
||||
@ -1352,13 +1362,16 @@ static int nla_server_init(rdpNla* nla)
|
||||
if (!nla_sspi_module_init(nla))
|
||||
return -1;
|
||||
|
||||
if (!nla_setup_kerberos(nla))
|
||||
return -1;
|
||||
|
||||
nla->status = nla_update_package_name(nla);
|
||||
|
||||
if (nla->status != SEC_E_OK)
|
||||
return -1;
|
||||
|
||||
nla->status =
|
||||
nla->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME, SECPKG_CRED_INBOUND, NULL, NULL,
|
||||
nla->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME, SECPKG_CRED_INBOUND, NULL, nla->identity,
|
||||
NULL, NULL, &nla->credentials, &nla->expiration);
|
||||
|
||||
if (nla->status != SEC_E_OK)
|
||||
|
@ -356,6 +356,7 @@ static const size_t string_list_indices[] = {
|
||||
FreeRDP_KerberosArmor,
|
||||
FreeRDP_KerberosCache,
|
||||
FreeRDP_KerberosKdc,
|
||||
FreeRDP_KerberosKeytab,
|
||||
FreeRDP_KerberosLifeTime,
|
||||
FreeRDP_KerberosRealm,
|
||||
FreeRDP_KerberosRenewableLifeTime,
|
||||
|
@ -71,6 +71,8 @@ int main(int argc, char** argv)
|
||||
"nla extended protocol security" },
|
||||
{ "sam-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL,
|
||||
"NTLM SAM file for NLA authentication" },
|
||||
{ "keytab", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL,
|
||||
"Kerberos keytab file for NLA authentication" },
|
||||
{ "gfx-progressive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
|
||||
"Allow GFX progressive codec" },
|
||||
{ "gfx-rfx", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
|
||||
|
@ -392,6 +392,10 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, arg->Value ? TRUE : FALSE))
|
||||
return COMMAND_LINE_ERROR;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "keytab")
|
||||
{
|
||||
freerdp_settings_set_string(settings, FreeRDP_KerberosKeytab, arg->Value);
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
}
|
||||
|
@ -601,6 +601,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* keytab;
|
||||
char* cache;
|
||||
char* armorCache;
|
||||
char* pkinitX509Anchors;
|
||||
|
@ -169,21 +169,23 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
|
||||
krb5_error_code rv;
|
||||
krb5_context ctx = NULL;
|
||||
krb5_ccache ccache = NULL;
|
||||
krb5_keytab keytab = NULL;
|
||||
krb5_get_init_creds_opt* gic_opt = NULL;
|
||||
krb5_deltat start_time = 0;
|
||||
krb5_principal principal = NULL;
|
||||
krb5_principal cache_principal = NULL;
|
||||
krb5_creds creds;
|
||||
BOOL is_unicode = FALSE;
|
||||
char* domain = NULL;
|
||||
char* username = NULL;
|
||||
char* password = NULL;
|
||||
char* ccache_name = NULL;
|
||||
char keytab_name[PATH_MAX];
|
||||
sspi_gss_OID_set_desc desired_mechs = { 1, SSPI_GSS_C_SPNEGO_KRB5 };
|
||||
sspi_gss_key_value_element_desc ccache_setting = { "ccache", ccache_name };
|
||||
sspi_gss_key_value_set_desc cred_store = { 1, &ccache_setting };
|
||||
sspi_gss_key_value_element_desc cred_store_opts[2];
|
||||
sspi_gss_key_value_set_desc cred_store = { 2, cred_store_opts };
|
||||
sspi_gss_cred_id_t gss_creds = NULL;
|
||||
OM_uint32 major, minor;
|
||||
char* fallback_cc_name = "MEMORY:";
|
||||
int cred_usage;
|
||||
|
||||
switch (fCredentialUse)
|
||||
@ -218,19 +220,14 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
|
||||
username = (char*)identity->User;
|
||||
password = (char*)identity->Password;
|
||||
}
|
||||
|
||||
if (!pszPrincipal)
|
||||
pszPrincipal = username;
|
||||
}
|
||||
|
||||
if ((rv = krb5_init_context(&ctx)))
|
||||
goto cleanup;
|
||||
|
||||
/* If user provided a cache use it whether or not it's initialized with the right principal */
|
||||
if (krb_settings && krb_settings->cache)
|
||||
{
|
||||
if ((rv = krb5_cc_set_default_name(ctx, krb_settings->cache)))
|
||||
goto cleanup;
|
||||
fallback_cc_name = krb_settings->cache;
|
||||
}
|
||||
|
||||
if (domain)
|
||||
{
|
||||
CharUpperA(domain);
|
||||
@ -239,36 +236,67 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (username)
|
||||
if (pszPrincipal)
|
||||
{
|
||||
/* Find realm component if included and convert to uppercase */
|
||||
char* p = username;
|
||||
for (; *p != '@' && *p != 0; p++)
|
||||
;
|
||||
char *p = strchr(pszPrincipal, '@');
|
||||
CharUpperA(p);
|
||||
|
||||
if ((rv = krb5_parse_name(ctx, username, &principal)))
|
||||
if ((rv = krb5_parse_name(ctx, pszPrincipal, &principal)))
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
|
||||
if (krb_settings && krb_settings->cache)
|
||||
{
|
||||
if ((rv = krb5_cc_resolve(ctx, krb_settings->cache, &ccache)))
|
||||
goto cleanup;
|
||||
|
||||
/* Make sure the cache is initialized with the right principal */
|
||||
if (principal)
|
||||
{
|
||||
if ((rv = krb5_cc_get_principal(ctx, ccache, &cache_principal)))
|
||||
goto cleanup;
|
||||
if (!krb5_principal_compare(ctx, principal, cache_principal))
|
||||
if ((rv = krb5_cc_initialize(ctx, ccache, principal)))
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else if (principal)
|
||||
{
|
||||
/* Use the default cache if it's initialized with the right principal */
|
||||
if (krb5_cc_cache_match(ctx, principal, &ccache) == KRB5_CC_NOTFOUND)
|
||||
{
|
||||
if ((rv = krb5_cc_resolve(ctx, "MEMORY:", &ccache)))
|
||||
goto cleanup;
|
||||
if ((rv = krb5_cc_initialize(ctx, ccache, principal)))
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else if (fCredentialUse & SECPKG_CRED_OUTBOUND)
|
||||
{
|
||||
/* Use the default cache with it's default principal */
|
||||
if ((rv = krb5_cc_default(ctx, &ccache)))
|
||||
goto cleanup;
|
||||
if ((rv = krb5_cc_get_principal(ctx, ccache, &principal)))
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* If the default (or user provided) cache is already initialized with the right principal use
|
||||
it otherwise initialize a new cache in memory (or the user provided one) with our principal
|
||||
*/
|
||||
if (krb5_cc_cache_match(ctx, principal, &ccache) == KRB5_CC_NOTFOUND)
|
||||
else
|
||||
{
|
||||
if ((rv = krb5_cc_resolve(ctx, fallback_cc_name, &ccache)))
|
||||
goto cleanup;
|
||||
if ((rv = krb5_cc_initialize(ctx, ccache, principal)))
|
||||
if ((rv = krb5_cc_resolve(ctx, "MEMORY:", &ccache)))
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (krb_settings && krb_settings->keytab)
|
||||
{
|
||||
if ((rv = krb5_kt_resolve(ctx, krb_settings->keytab, &keytab)))
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((rv = krb5_kt_default(ctx, &keytab)))
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt)))
|
||||
goto cleanup;
|
||||
|
||||
@ -301,15 +329,22 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
|
||||
#endif
|
||||
|
||||
krb5_cc_get_full_name(ctx, ccache, &ccache_name);
|
||||
ccache_setting.value = ccache_name;
|
||||
krb5_kt_get_name(ctx, keytab, keytab_name, PATH_MAX);
|
||||
|
||||
cred_store_opts[0].key = "ccache";
|
||||
cred_store_opts[0].value = ccache_name;
|
||||
cred_store_opts[1].key = "keytab";
|
||||
cred_store_opts[1].value = keytab_name;
|
||||
|
||||
/* Check if there are initial creds already in the cache there's no need to request new ones */
|
||||
major = sspi_gss_acquire_cred_from(&minor, SSPI_GSS_C_NO_NAME, SSPI_GSS_C_INDEFINITE,
|
||||
&desired_mechs, SSPI_GSS_C_INITIATE, &cred_store, &gss_creds,
|
||||
&desired_mechs, cred_usage, &cred_store, &gss_creds,
|
||||
NULL, NULL);
|
||||
if (major != SSPI_GSS_S_NO_CRED)
|
||||
goto cleanup;
|
||||
|
||||
gss_log_status_messages(major, minor);
|
||||
|
||||
if ((rv = krb5_get_init_creds_password(ctx, &creds, principal, password, krb5_prompter,
|
||||
password, start_time, NULL, gic_opt)))
|
||||
goto cleanup;
|
||||
@ -343,7 +378,7 @@ cleanup:
|
||||
if (password)
|
||||
free(password);
|
||||
}
|
||||
if (ccache_setting.value)
|
||||
if (ccache_name)
|
||||
krb5_free_string(ctx, ccache_name);
|
||||
if (principal)
|
||||
krb5_free_principal(ctx, principal);
|
||||
@ -556,6 +591,82 @@ static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW(
|
||||
return status;
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY kerberos_AcceptSecurityContext(
|
||||
PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq,
|
||||
ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpity)
|
||||
{
|
||||
#ifdef WITH_GSSAPI
|
||||
KRB_CONTEXT *context;
|
||||
sspi_gss_cred_id_t creds;
|
||||
sspi_gss_ctx_id_t gss_ctx = SSPI_GSS_C_NO_CONTEXT;
|
||||
PSecBuffer input_buffer;
|
||||
PSecBuffer output_buffer = NULL;
|
||||
sspi_gss_buffer_desc input_token;
|
||||
sspi_gss_buffer_desc output_token;
|
||||
UINT32 major, minor;
|
||||
UINT32 time_rec;
|
||||
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
creds = sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (pInput)
|
||||
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
|
||||
if (pOutput)
|
||||
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
|
||||
|
||||
if (!input_buffer)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (context)
|
||||
gss_ctx = context->gss_ctx;
|
||||
|
||||
input_token.length = input_buffer->cbBuffer;
|
||||
input_token.value = input_buffer->pvBuffer;
|
||||
|
||||
major = sspi_gss_accept_sec_context(
|
||||
&minor, &gss_ctx, creds, &input_token, SSPI_GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, &output_token, pfContextAttr, &time_rec, NULL);
|
||||
|
||||
if (SSPI_GSS_ERROR(major))
|
||||
{
|
||||
gss_log_status_messages(major, minor);
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (output_token.length > 0)
|
||||
{
|
||||
if (output_buffer && output_buffer->cbBuffer >= output_token.length)
|
||||
{
|
||||
output_buffer->cbBuffer = output_token.length;
|
||||
CopyMemory(output_buffer->pvBuffer, output_token.value, output_token.length);
|
||||
sspi_gss_release_buffer(&minor, &output_token);
|
||||
}
|
||||
else
|
||||
{
|
||||
sspi_gss_release_buffer(&minor, &output_token);
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = kerberos_ContextNew();
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
context->gss_ctx = gss_ctx;
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, KERBEROS_SSP_NAME);
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
|
||||
if (major & SSPI_GSS_S_CONTINUE_NEEDED)
|
||||
return SEC_I_CONTINUE_NEEDED;
|
||||
|
||||
return SEC_E_OK;
|
||||
#else
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
#endif /* WITH_GSSAPI */
|
||||
}
|
||||
|
||||
static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
KRB_CONTEXT* context;
|
||||
@ -852,7 +963,7 @@ const SecurityFunctionTableA KERBEROS_SecurityFunctionTableA = {
|
||||
kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
NULL, /* Reserved2 */
|
||||
kerberos_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
NULL, /* AcceptSecurityContext */
|
||||
kerberos_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
kerberos_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
@ -883,7 +994,7 @@ const SecurityFunctionTableW KERBEROS_SecurityFunctionTableW = {
|
||||
kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
NULL, /* Reserved2 */
|
||||
kerberos_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
NULL, /* AcceptSecurityContext */
|
||||
kerberos_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
kerberos_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
|
@ -55,8 +55,8 @@ struct Mech_st
|
||||
{
|
||||
const sspi_gss_OID_desc* oid;
|
||||
const SecPkg* pkg;
|
||||
const UINT init_flags;
|
||||
const UINT accept_flags;
|
||||
const UINT flags;
|
||||
const BOOL preferred;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@ -101,8 +101,8 @@ static const SecPkg SecPkgTable[] = {
|
||||
};
|
||||
|
||||
static const Mech MechTable[] = {
|
||||
{ &kerberos_OID, &SecPkgTable[0], 0, 0 },
|
||||
{ &ntlm_OID, &SecPkgTable[1], 0, 0 },
|
||||
{ &kerberos_OID, &SecPkgTable[0], 0, TRUE },
|
||||
{ &ntlm_OID, &SecPkgTable[1], 0, FALSE },
|
||||
};
|
||||
|
||||
static const int MECH_COUNT = sizeof(MechTable) / sizeof(Mech);
|
||||
@ -671,7 +671,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
|
||||
CopyMemory(&output_token.mechToken, output_buffer, sizeof(SecBuffer));
|
||||
|
||||
status = MechTable[i].pkg->table_w->InitializeSecurityContextW(
|
||||
&creds[i].cred, NULL, pszTargetName, fContextReq | creds[i].mech->init_flags,
|
||||
&creds[i].cred, NULL, pszTargetName, fContextReq | creds[i].mech->flags,
|
||||
Reserved1, TargetDataRep, NULL, Reserved2, &init_context.sub_context, &mech_output,
|
||||
pfContextAttr, ptsExpiry);
|
||||
|
||||
@ -802,7 +802,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
|
||||
CopyMemory(&output_token.mechToken, output_buffer, sizeof(SecBuffer));
|
||||
|
||||
status = context->mech->pkg->table_w->InitializeSecurityContextW(
|
||||
sub_cred, sub_context, pszTargetName, fContextReq | context->mech->init_flags,
|
||||
sub_cred, sub_context, pszTargetName, fContextReq | context->mech->flags,
|
||||
Reserved1, TargetDataRep, input_token.mechToken.cbBuffer ? &mech_input : NULL,
|
||||
Reserved2, &context->sub_context, &mech_output, pfContextAttr, ptsExpiry);
|
||||
|
||||
@ -894,6 +894,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
|
||||
BYTE *p, tag;
|
||||
size_t bytes_remain, len;
|
||||
sspi_gss_OID_desc oid = { 0 };
|
||||
const Mech* first_mech = NULL;
|
||||
|
||||
if (!phCredential || !SecIsValidHandle(phCredential))
|
||||
return SEC_E_NO_CREDENTIALS;
|
||||
@ -971,6 +972,8 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
|
||||
|
||||
oid.length = len;
|
||||
oid.elements = p;
|
||||
p += len;
|
||||
bytes_remain -= len;
|
||||
|
||||
init_context.mech = negotiate_GetMechByOID(oid);
|
||||
|
||||
@ -1009,7 +1012,9 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
|
||||
return status;
|
||||
|
||||
init_context.mic = TRUE;
|
||||
first_mech = init_context.mech;
|
||||
init_context.mech = NULL;
|
||||
output_token.mechToken.cbBuffer = 0;
|
||||
}
|
||||
|
||||
while (!init_context.mech && bytes_remain > 0)
|
||||
@ -1021,8 +1026,15 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
|
||||
|
||||
oid.length = len;
|
||||
oid.elements = p;
|
||||
p += len;
|
||||
bytes_remain -= len;
|
||||
|
||||
init_context.mech = negotiate_GetMechByOID(oid);
|
||||
|
||||
/* Microsoft may send two versions of the kerberos OID */
|
||||
if (init_context.mech == first_mech)
|
||||
init_context.mech = NULL;
|
||||
|
||||
if (init_context.mech && !negotiate_FindCredential(creds, init_context.mech))
|
||||
init_context.mech = NULL;
|
||||
}
|
||||
@ -1047,22 +1059,21 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
|
||||
CopyMemory(init_context.mechTypes.pvBuffer, input_token.mechTypes.pvBuffer,
|
||||
input_token.mechTypes.cbBuffer);
|
||||
|
||||
/* Check if the chosen mechanism is our most preferred; otherwise request mic */
|
||||
for (int i = 0; i < MECH_COUNT; i++)
|
||||
if (!context->mech->preferred)
|
||||
{
|
||||
if (context->mech != creds[i].mech)
|
||||
{
|
||||
output_token.negState = REQUEST_MIC;
|
||||
context->mic = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_token.negState = ACCEPT_INCOMPLETE;
|
||||
}
|
||||
break;
|
||||
output_token.negState = REQUEST_MIC;
|
||||
context->mic = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_token.negState = ACCEPT_INCOMPLETE;
|
||||
}
|
||||
|
||||
context->state = NEGOTIATE_STATE_NEGORESP;
|
||||
if (status == SEC_E_OK)
|
||||
context->state = NEGOTIATE_STATE_FINAL;
|
||||
else
|
||||
context->state = NEGOTIATE_STATE_NEGORESP;
|
||||
|
||||
output_token.supportedMech.length = oid.length;
|
||||
output_token.supportedMech.elements = oid.elements;
|
||||
WLog_DBG(TAG, "Accepted mechanism: %s", negotiate_mech_name(&output_token.supportedMech));
|
||||
@ -1094,7 +1105,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
|
||||
|
||||
status = context->mech->pkg->table->AcceptSecurityContext(
|
||||
sub_cred, &context->sub_context, &mech_input,
|
||||
fContextReq | context->mech->accept_flags, TargetDataRep, &context->sub_context,
|
||||
fContextReq | context->mech->flags, TargetDataRep, &context->sub_context,
|
||||
pOutput, pfContextAttr, ptsTimeStamp);
|
||||
|
||||
if (IsSecurityStatusError(status))
|
||||
|
Loading…
Reference in New Issue
Block a user