Example #1
0
static uint32_t NetSecurityNative_AcquireCredSpNego(uint32_t* minorStatus,
                                                    GssName* desiredName,
                                                    gss_cred_usage_t credUsage,
                                                    GssCredId** outputCredHandle)
{
    assert(minorStatus != NULL);
    assert(desiredName != NULL);
    assert(outputCredHandle != NULL);
    assert(*outputCredHandle == NULL);

#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = GSS_SPNEGO_MECHANISM};
#else
    gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = &gss_mech_spnego_OID_desc};
#endif
    uint32_t majorStatus = gss_acquire_cred(
        minorStatus, desiredName, 0, &gss_mech_spnego_OID_set_desc, credUsage, outputCredHandle, NULL, NULL);

    // call gss_set_cred_option with GSS_KRB5_CRED_NO_CI_FLAGS_X to support Kerberos Sign Only option from *nix client against a windows server
#if HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
    if (majorStatus == GSS_S_COMPLETE)
    {
        GssBuffer emptyBuffer = GSS_C_EMPTY_BUFFER;
        majorStatus = gss_set_cred_option(minorStatus, outputCredHandle, GSS_KRB5_CRED_NO_CI_FLAGS_X, &emptyBuffer);
    }
#endif

    return majorStatus;
}

uint32_t
NetSecurityNative_InitiateCredSpNego(uint32_t* minorStatus, GssName* desiredName, GssCredId** outputCredHandle)
{
    return NetSecurityNative_AcquireCredSpNego(minorStatus, desiredName, GSS_C_INITIATE, outputCredHandle);
}

uint32_t NetSecurityNative_DeleteSecContext(uint32_t* minorStatus, GssCtxId** contextHandle)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);

    return gss_delete_sec_context(minorStatus, contextHandle, GSS_C_NO_BUFFER);
}

static uint32_t NetSecurityNative_DisplayStatus(uint32_t* minorStatus,
                                                uint32_t statusValue,
                                                int statusType,
                                                PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(outBuffer != NULL);

    uint32_t messageContext = 0; // Must initialize to 0 before calling gss_display_status.
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    uint32_t majorStatus =
        gss_display_status(minorStatus, statusValue, statusType, GSS_C_NO_OID, &messageContext, &gssBuffer);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t
NetSecurityNative_DisplayMinorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer)
{
    return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_MECH_CODE, outBuffer);
}

uint32_t
NetSecurityNative_DisplayMajorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer)
{
    return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_GSS_CODE, outBuffer);
}

uint32_t
NetSecurityNative_ImportUserName(uint32_t* minorStatus, char* inputName, uint32_t inputNameLen, GssName** outputName)
{
    assert(minorStatus != NULL);
    assert(inputName != NULL);
    assert(outputName != NULL);
    assert(*outputName == NULL);

    GssBuffer inputNameBuffer = {.length = inputNameLen, .value = inputName};
    return gss_import_name(minorStatus, &inputNameBuffer, GSS_C_NT_USER_NAME, outputName);
}
Example #2
0
uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
                                          GssCredId* claimantCredHandle,
                                          GssCtxId** contextHandle,
                                          uint32_t isNtlm,
                                          void* cbt,
                                          int32_t cbtSize,
                                          int32_t isNtlmFallback,
                                          GssName* targetNameKerberos,
                                          GssName* targetNameNtlm,
                                          uint32_t reqFlags,
                                          uint8_t* inputBytes,
                                          uint32_t inputLength,
                                          PAL_GssBuffer* outBuffer,
                                          uint32_t* retFlags,
                                          int32_t* isNtlmUsed)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(isNtlm == 0 || isNtlm == 1);
    assert(isNtlm == 1 || targetNameKerberos != NULL);
    assert(isNtlmFallback == 0 || isNtlmFallback == 1);
    assert(targetNameNtlm != NULL);
    assert(inputBytes != NULL || inputLength == 0);
    assert(outBuffer != NULL);
    assert(retFlags != NULL);
    assert(isNtlmUsed != NULL);
    assert(cbt != NULL || cbtSize == 0);

// Note: claimantCredHandle can be null
// Note: *contextHandle is null only in the first call and non-null in the subsequent calls

#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID desiredMech;
    if (isNtlm)
    {
        desiredMech = GSS_NTLM_MECHANISM;
    }
    else
    {
        desiredMech = GSS_SPNEGO_MECHANISM;
    }

    gss_OID krbMech = GSS_KRB5_MECHANISM;
#else
    gss_OID_desc gss_mech_OID_desc;
    if (isNtlm)
    {
        gss_mech_OID_desc = gss_mech_ntlm_OID_desc;
    }
    else
    {
        gss_mech_OID_desc = gss_mech_spnego_OID_desc;
    }

    gss_OID desiredMech = &gss_mech_OID_desc;
    gss_OID krbMech = gss_mech_krb5;
#endif

    *isNtlmUsed = 1;
    GssBuffer inputToken = {.length = inputLength, .value = inputBytes};
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    gss_OID_desc* outmech;

    struct gss_channel_bindings_struct gssCbt;
    if (cbt != NULL)
    {
        memset(&gssCbt, 0, sizeof(struct gss_channel_bindings_struct));
        gssCbt.application_data.length = (size_t)cbtSize;
        gssCbt.application_data.value = cbt;
    }

    GssName* targetName;
    if (isNtlm || isNtlmFallback)
    {
        targetName = targetNameNtlm;
    }
    else
    {
        targetName = targetNameKerberos;
    }
    
    uint32_t majorStatus;
    uint32_t retryCount = 0;
    bool retry;
    do
    {
        majorStatus = gss_init_sec_context(minorStatus,
                                           claimantCredHandle,
                                           contextHandle,
                                           targetName,
                                           desiredMech,
                                           reqFlags,
                                           0,
                                           (cbt != NULL) ? &gssCbt : GSS_C_NO_CHANNEL_BINDINGS,
                                           &inputToken,
                                           &outmech,
                                           &gssBuffer,
                                           retFlags,
                                           NULL);

        // If SPNEGO fails to generate optimistic Kerberos token on initial call then fall back to SPNEGO-wrapped NTLM.
        retry = false;
        if ((majorStatus == GSS_S_FAILURE || majorStatus == GSS_S_BAD_NAMETYPE) &&
            *contextHandle == NULL && !isNtlm && ++retryCount <= 1)
        {
            targetName = targetNameNtlm;
            retry = true;
        }
    } while (retry);

    // Outmech can be null when gssntlmssp lib uses NTLM mechanism
    if (outmech != NULL && gss_oid_equal(outmech, krbMech) != 0)
    {
        *isNtlmUsed = 0;
    }

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                            GssCtxId** contextHandle,
                                            uint8_t* inputBytes,
                                            uint32_t inputLength,
                                            PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(inputBytes != NULL || inputLength == 0);
    assert(outBuffer != NULL);
    // Note: *contextHandle is null only in the first call and non-null in the subsequent calls

    GssBuffer inputToken = {.length = inputLength, .value = inputBytes};
    GssBuffer gssBuffer = {.length = 0, .value = NULL};

    uint32_t majorStatus = gss_accept_sec_context(minorStatus,
                                                  contextHandle,
                                                  GSS_C_NO_CREDENTIAL,
                                                  &inputToken,
                                                  GSS_C_NO_CHANNEL_BINDINGS,
                                                  NULL,
                                                  NULL,
                                                  &gssBuffer,
                                                  0,
                                                  NULL,
                                                  NULL);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t NetSecurityNative_ReleaseCred(uint32_t* minorStatus, GssCredId** credHandle)
{
    assert(minorStatus != NULL);
    assert(credHandle != NULL);

    return gss_release_cred(minorStatus, credHandle);
}
Example #3
0
uint32_t NetSecurityNative_Wrap(uint32_t* minorStatus,
                                GssCtxId* contextHandle,
                                int32_t isEncrypt,
                                uint8_t* inputBytes,
                                int32_t offset,
                                int32_t count,
                                PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(isEncrypt == 1 || isEncrypt == 0);
    assert(inputBytes != NULL);
    assert(offset >= 0);
    assert(count >= 0);
    assert(outBuffer != NULL);
    // count refers to the length of the input message. That is, number of bytes of inputBytes
    // starting at offset that need to be wrapped.

    int confState;
    GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset};
    GssBuffer gssBuffer;
    uint32_t majorStatus =
        gss_wrap(minorStatus, contextHandle, isEncrypt, GSS_C_QOP_DEFAULT, &inputMessageBuffer, &confState, &gssBuffer);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t NetSecurityNative_Unwrap(uint32_t* minorStatus,
                                  GssCtxId* contextHandle,
                                  uint8_t* inputBytes,
                                  int32_t offset,
                                  int32_t count,
                                  PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(inputBytes != NULL);
    assert(offset >= 0);
    assert(count >= 0);
    assert(outBuffer != NULL);

    // count refers to the length of the input message. That is, the number of bytes of inputBytes
    // starting at offset that need to be wrapped.
    GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset};
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    uint32_t majorStatus = gss_unwrap(minorStatus, contextHandle, &inputMessageBuffer, &gssBuffer, NULL, NULL);
    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

static uint32_t NetSecurityNative_AcquireCredWithPassword(uint32_t* minorStatus,
                                                          int32_t isNtlm,
                                                          GssName* desiredName,
                                                          char* password,
                                                          uint32_t passwdLen,
                                                          gss_cred_usage_t credUsage,
                                                          GssCredId** outputCredHandle)
{
    assert(minorStatus != NULL);
    assert(isNtlm == 1 || isNtlm == 0);
    assert(desiredName != NULL);
    assert(password != NULL);
    assert(outputCredHandle != NULL);
    assert(*outputCredHandle == NULL);

#if HAVE_GSS_SPNEGO_MECHANISM
    (void)isNtlm; // unused
    // Specifying GSS_SPNEGO_MECHANISM as a desiredMech on OSX fails.
    gss_OID_set desiredMech = GSS_C_NO_OID_SET;
#else
    gss_OID_desc gss_mech_OID_desc;
    if (isNtlm)
    {
        gss_mech_OID_desc = gss_mech_ntlm_OID_desc;
    }
    else
    {
        gss_mech_OID_desc = gss_mech_spnego_OID_desc;
    }

    gss_OID_set_desc gss_mech_OID_set_desc = {.count = 1, .elements = &gss_mech_OID_desc};
    gss_OID_set desiredMech = &gss_mech_OID_set_desc;
#endif

    GssBuffer passwordBuffer = {.length = passwdLen, .value = password};
    uint32_t majorStatus = gss_acquire_cred_with_password(
        minorStatus, desiredName, &passwordBuffer, 0, desiredMech, credUsage, outputCredHandle, NULL, NULL);

    // call gss_set_cred_option with GSS_KRB5_CRED_NO_CI_FLAGS_X to support Kerberos Sign Only option from *nix client against a windows server
#if HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
    if (majorStatus == GSS_S_COMPLETE)
    {
        GssBuffer emptyBuffer = GSS_C_EMPTY_BUFFER;
        majorStatus = gss_set_cred_option(minorStatus, outputCredHandle, GSS_KRB5_CRED_NO_CI_FLAGS_X, &emptyBuffer);
    }
#endif

    return majorStatus;
}

uint32_t NetSecurityNative_InitiateCredWithPassword(uint32_t* minorStatus,
                                                    int32_t isNtlm,
                                                    GssName* desiredName,
                                                    char* password,
                                                    uint32_t passwdLen,
                                                    GssCredId** outputCredHandle)
{
    return NetSecurityNative_AcquireCredWithPassword(
        minorStatus, isNtlm, desiredName, password, passwdLen, GSS_C_INITIATE, outputCredHandle);
}

uint32_t NetSecurityNative_IsNtlmInstalled()
{
#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID ntlmOid = GSS_NTLM_MECHANISM;
#else
    gss_OID ntlmOid = &gss_mech_ntlm_OID_desc;
#endif

    uint32_t majorStatus;
    uint32_t minorStatus;
    gss_OID_set mechSet;
    gss_OID_desc oid;
    uint32_t foundNtlm = 0;

    majorStatus = gss_indicate_mechs(&minorStatus, &mechSet);
    if (majorStatus == GSS_S_COMPLETE)
    {
        for (size_t i = 0; i < mechSet->count; i++)
        {
            oid = mechSet->elements[i];
            if ((oid.length == ntlmOid->length) && (memcmp(oid.elements, ntlmOid->elements, oid.length) == 0))
            {
                foundNtlm = 1;
                break;
            }
        }

        gss_release_oid_set(&minorStatus, &mechSet);
    }

    return foundNtlm;
}
Example #4
0
uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
                                          GssCredId* claimantCredHandle,
                                          GssCtxId** contextHandle,
                                          uint32_t isNtlm,
                                          void* cbt,
                                          int32_t cbtSize,
                                          GssName* targetName,
                                          uint32_t reqFlags,
                                          uint8_t* inputBytes,
                                          uint32_t inputLength,
                                          PAL_GssBuffer* outBuffer,
                                          uint32_t* retFlags,
                                          int32_t* isNtlmUsed)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(isNtlm == 0 || isNtlm == 1);
    assert(targetName != NULL);
    assert(inputBytes != NULL || inputLength == 0);
    assert(outBuffer != NULL);
    assert(retFlags != NULL);
    assert(isNtlmUsed != NULL);
    assert(cbt != NULL || cbtSize == 0);

// Note: claimantCredHandle can be null
// Note: *contextHandle is null only in the first call and non-null in the subsequent calls

#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID krbMech = GSS_KRB5_MECHANISM;
    gss_OID desiredMech;
    if (isNtlm)
    {
        desiredMech = GSS_NTLM_MECHANISM;
    }
    else
    {
        desiredMech = GSS_SPNEGO_MECHANISM;
    }
#else
    gss_OID krbMech = (gss_OID)(unsigned long)gss_mech_krb5;
    gss_OID_desc gss_mech_OID_desc;
    if (isNtlm)
    {
        gss_mech_OID_desc = gss_mech_ntlm_OID_desc;
    }
    else
    {
        gss_mech_OID_desc = gss_mech_spnego_OID_desc;
    }

    gss_OID desiredMech = &gss_mech_OID_desc;
#endif

    GssBuffer inputToken = {.length = inputLength, .value = inputBytes};
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    gss_OID_desc* outmech;

    struct gss_channel_bindings_struct gssCbt;
    if (cbt != NULL)
    {
        memset(&gssCbt, 0, sizeof(struct gss_channel_bindings_struct));
        gssCbt.application_data.length = (size_t)cbtSize;
        gssCbt.application_data.value = cbt;
    }

    uint32_t majorStatus = gss_init_sec_context(minorStatus,
                                                claimantCredHandle,
                                                contextHandle,
                                                targetName,
                                                desiredMech,
                                                reqFlags,
                                                0,
                                                (cbt != NULL) ? &gssCbt : GSS_C_NO_CHANNEL_BINDINGS,
                                                &inputToken,
                                                &outmech,
                                                &gssBuffer,
                                                retFlags,
                                                NULL);

    *isNtlmUsed = (isNtlm || majorStatus != GSS_S_COMPLETE || gss_oid_equal(outmech, krbMech) == 0) ? 1 : 0;

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                            GssCtxId** contextHandle,
                                            uint8_t* inputBytes,
                                            uint32_t inputLength,
                                            PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(inputBytes != NULL || inputLength == 0);
    assert(outBuffer != NULL);
    // Note: *contextHandle is null only in the first call and non-null in the subsequent calls

    GssBuffer inputToken = {.length = inputLength, .value = inputBytes};
    GssBuffer gssBuffer = {.length = 0, .value = NULL};

    uint32_t majorStatus = gss_accept_sec_context(minorStatus,
                                                  contextHandle,
                                                  GSS_C_NO_CREDENTIAL,
                                                  &inputToken,
                                                  GSS_C_NO_CHANNEL_BINDINGS,
                                                  NULL,
                                                  NULL,
                                                  &gssBuffer,
                                                  0,
                                                  NULL,
                                                  NULL);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t NetSecurityNative_ReleaseCred(uint32_t* minorStatus, GssCredId** credHandle)
{
    assert(minorStatus != NULL);
    assert(credHandle != NULL);

    return gss_release_cred(minorStatus, credHandle);
}