Ejemplo n.º 1
0
/**
 * Covert AD object's SID to an ASCII string.
 *
 * @param s Bytes to convert.
 * @param out Converted string.
 * @return 0 on success; error code on failure.
 */
DWORD Sid2Str(IN PVOID s, OUT PSTR *out)
{
    DWORD dwError = 0;
    size_t size = 0;
    INT count = 0;
    ULONG i = 0;
    SidTP sid = (SidTP) s;

    *out = NULL;

    size = 2 + 3 + 1 + 14 + (1 + 10) * sid->SubAuthorityCount + 1;

    dwError = LwAllocateMemory(size * sizeof(char), OUT_PPVOID(out));
    ADT_BAIL_ON_ALLOC_FAILURE_NP(!dwError);

    if (sid->IdentifierAuthority[0] || sid->IdentifierAuthority[1]) {
        count += snprintf(*out + count, size - count,
                          "S-%u-0x%.2X%.2X%.2X%.2X%.2X%.2X", sid->Revision,
                          sid->IdentifierAuthority[0],
                          sid->IdentifierAuthority[1],
                          sid->IdentifierAuthority[2],
                          sid->IdentifierAuthority[3],
                          sid->IdentifierAuthority[4],
                          sid->IdentifierAuthority[5]);
    }
    else {
        ULONG value = 0;

        value |= (ULONG) sid->IdentifierAuthority[5];
        value |= (ULONG) sid->IdentifierAuthority[4] << 8;
        value |= (ULONG) sid->IdentifierAuthority[3] << 16;
        value |= (ULONG) sid->IdentifierAuthority[2] << 24;

        count += snprintf(*out  + count, size - count, "S-%u-%u",
                          sid->Revision, value);
    }

    for (i = 0; i < sid->SubAuthorityCount; i++) {
#if defined(WORDS_BIGENDIAN)
        sid->SubAuthority[i] = LW_ENDIAN_SWAP32(sid->SubAuthority[i]);
#endif
        count += snprintf(*out  + count, size - count, "-%u", sid->SubAuthority[i]);
    }

    cleanup:
       return dwError;

    error:
       LW_SAFE_FREE_MEMORY(*out);
       goto cleanup;
}
Ejemplo n.º 2
0
DWORD
LWNetReadLEDword(
    OUT PDWORD pdwDest,
    IN PACKED_ARRAY* pArray
)
{
    if (pArray->totalSize + pArray->pStart - pArray->pCur < sizeof(DWORD))
    {
        return DNS_ERROR_BAD_PACKET;
    }
#if defined(WORDS_BIGENDIAN)
    *pdwDest = LW_ENDIAN_SWAP32(LWNetReadUnalignedDword(pArray->pCur));
#else
    *pdwDest = LWNetReadUnalignedDword(pArray->pCur);
#endif
    pArray->pCur += sizeof(DWORD);
    return ERROR_SUCCESS;
}
Ejemplo n.º 3
0
/**
 * Generate UID from SID.
 *
 * @param s SID bytes.
 * @param out UID (dynamically allocated).
 * @return 0 on success; error code on failure.
 */
DWORD Sid2Id(IN PVOID s, OUT PDWORD out)
{
    DWORD dwError = 0;
    size_t size = 0;
    SidTP sid = (SidTP) s;
    PDWORD subs = NULL;

    *out = 0;

    if (sid->Revision != 1)
    {
        dwError = ADT_ERR_INVALID_SID;
        ADT_BAIL_ON_ERROR_NP(dwError);
    }

    size = sid->SubAuthorityCount * sizeof(DWORD);

    dwError = LwAllocateMemory(size, OUT_PPVOID(&subs));
    ADT_BAIL_ON_ALLOC_FAILURE_NP(!dwError);

    memcpy((PVOID)subs, (PVOID) sid->SubAuthority, size);

#if defined(WORDS_BIGENDIAN)
    INT i;

    for (i = 0; i < sid->SubAuthorityCount; i++)
    {
        subs[i] = LW_ENDIAN_SWAP32(subs[i]);
    }
#endif

    LwUidHashCalc(subs, sid->SubAuthorityCount, out);

    cleanup:
        LW_SAFE_FREE_MEMORY(subs);
       return dwError;

    error:
       goto cleanup;
}
Ejemplo n.º 4
0
DWORD
LwKrb5VerifyPac(
    krb5_context ctx,
    const krb5_ticket *pTgsTicket,
    const struct berval *pPacBerVal,
    const krb5_keyblock *serviceKey,
    char** ppchLogonInfo,
    size_t* psLogonInfo
    )
{
    krb5_error_code ret = 0;
    PAC_DATA *pPacData = NULL;
    DWORD i;
    char *pchPacCopy = NULL;
    //Do not free
    krb5_data krbPacData = {0};
    //Do not free
    krb5_checksum checksum = {0};
    //Do not free
    PAC_SIGNATURE_DATA *pServerSig = NULL;
    PAC_LOGON_NAME *pLogonName = NULL;
    size_t sServerSig = 0;
    //Do not free
    char *pchLogonInfoStart = NULL;
    size_t sLogonInfoLen = 0;
    krb5_boolean bHasGoodChecksum = FALSE;
    uint64_t qwNtAuthTime;
    DWORD dwError = LW_ERROR_SUCCESS;
    //Free with krb5_free_unparsed_name
    PSTR pszClientPrincipal = NULL;
    PSTR pszLogonName = NULL;
    char* pchLogonInfo = NULL;

    #if defined(WORDS_BIGENDIAN)
    WORD * pwNameLocal = NULL;
    DWORD dwCount = 0;
    #endif

    dwError = LwAllocateMemory(
                pPacBerVal->bv_len,
                OUT_PPVOID(&pPacData));
    BAIL_ON_LW_ERROR(dwError);

    memcpy(pPacData, pPacBerVal->bv_val, pPacBerVal->bv_len);

    #if defined(WORDS_BIGENDIAN)
        pPacData->dwBufferCount = LW_ENDIAN_SWAP32(pPacData->dwBufferCount);
        pPacData->dwVersion = LW_ENDIAN_SWAP32(pPacData->dwVersion);
    #endif

    // We only know about version 0
    if (pPacData->dwVersion != 0)
    {
        dwError = LW_ERROR_INVALID_MESSAGE;
        BAIL_ON_LW_ERROR(dwError);
    }
    // Make sure that the last buffer in the pac data doesn't go out of bounds
    // of the parent buffer
    if ((void *)&pPacData->buffers[pPacData->dwBufferCount] -
            (void *)pPacData > pPacBerVal->bv_len)
    {
        dwError = LW_ERROR_INVALID_MESSAGE;
        BAIL_ON_LW_ERROR(dwError);
    }

    // Make sure the data associated with each buffer doesn't go out of
    // bounds
    for (i = 0; i < pPacData->dwBufferCount; i++)
    {
        #if defined(WORDS_BIGENDIAN)
            pPacData->buffers[i].dwType = LW_ENDIAN_SWAP32(pPacData->buffers[i].dwType);
            pPacData->buffers[i].dwSize = LW_ENDIAN_SWAP32(pPacData->buffers[i].dwSize);
            pPacData->buffers[i].qwOffset = LW_ENDIAN_SWAP64(pPacData->buffers[i].qwOffset);
        #endif

        if (pPacData->buffers[i].qwOffset + pPacData->buffers[i].dwSize <
                pPacData->buffers[i].qwOffset)
        {
            dwError = LW_ERROR_INVALID_MESSAGE;
            BAIL_ON_LW_ERROR(dwError);
        }
        if (pPacData->buffers[i].qwOffset + pPacData->buffers[i].dwSize >
                pPacBerVal->bv_len)
        {
            dwError = LW_ERROR_INVALID_MESSAGE;
            BAIL_ON_LW_ERROR(dwError);
        }
    }

    dwError = LwAllocateMemory(
                pPacBerVal->bv_len,
                OUT_PPVOID(&pchPacCopy));
    BAIL_ON_LW_ERROR(dwError);

    memcpy(pchPacCopy, pPacBerVal->bv_val, pPacBerVal->bv_len);

    krbPacData.magic = KV5M_DATA;
    krbPacData.length = pPacBerVal->bv_len;
    krbPacData.data = pchPacCopy;

    for (i = 0; i < pPacData->dwBufferCount; i++)
    {
    	switch (pPacData->buffers[i].dwType)
    	{
    	    case PAC_TYPE_LOGON_INFO:
    	        pchLogonInfoStart = (char *)pPacData + pPacData->buffers[i].qwOffset;
                sLogonInfoLen = pPacData->buffers[i].dwSize;
                break;
            case PAC_TYPE_SRV_CHECKSUM:
                pServerSig = (PAC_SIGNATURE_DATA *)((char *)pPacData +
                             pPacData->buffers[i].qwOffset);

                #if defined(WORDS_BIGENDIAN)
                    pServerSig->dwType = LW_ENDIAN_SWAP32(pServerSig->dwType);
                #endif

                sServerSig = pPacData->buffers[i].dwSize -
                        (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature;
                /* The checksum is calculated with the signatures zeroed out. */
                memset(pchPacCopy + pPacData->buffers[i].qwOffset +
                       (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature,
                       0,
                       pPacData->buffers[i].dwSize -
                           (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature);
                break;
            case PAC_TYPE_KDC_CHECKSUM:
                /* The checksum is calculated with the signatures zeroed out. */
    		memset(pchPacCopy + pPacData->buffers[i].qwOffset +
    	               (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature,
    		       0,
    		       pPacData->buffers[i].dwSize -
    		           (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature);
    		break;
            case PAC_TYPE_LOGON_NAME:
                pLogonName = (PAC_LOGON_NAME *)((char *)pPacData +
                             pPacData->buffers[i].qwOffset);

                #if defined(WORDS_BIGENDIAN)
                    pLogonName->ticketTime = LW_ENDIAN_SWAP64(pLogonName->ticketTime);
                    pLogonName->wAccountNameLen = LW_ENDIAN_SWAP16(pLogonName->wAccountNameLen);
                    pwNameLocal = pLogonName->pwszName;

                    for ( dwCount = 0 ;
                          dwCount < pLogonName->wAccountNameLen / 2 ;
                          dwCount++ )
                    {
                        pwNameLocal[dwCount] = LW_ENDIAN_SWAP16(pwNameLocal[dwCount]);
                    }
                #endif

                if ((char *)&pLogonName->pwszName +
                    pLogonName->wAccountNameLen >
                    (char *)pPacData + pPacData->buffers[i].qwOffset +
                    pPacData->buffers[i].dwSize)
                {
                    // The message is invalid because the terminating null
                    // of the name lands outside of the buffer.
                    dwError = LW_ERROR_INVALID_MESSAGE;
                    BAIL_ON_LW_ERROR(dwError);
                }
                break;
            default:
                break;
    	}
    }

    if (pServerSig == NULL)
    {
        dwError = LW_ERROR_INVALID_MESSAGE;
        BAIL_ON_LW_ERROR(dwError);
    }

    if (pLogonName == NULL)
    {
        //We need the logon name to verify the pac is for the right user
        dwError = LW_ERROR_INVALID_MESSAGE;
        BAIL_ON_LW_ERROR(dwError);
    }

    if (pchLogonInfoStart == NULL)
    {
        /* The buffer we really care about isn't in the pac. */
        dwError = LW_ERROR_INVALID_MESSAGE;
        BAIL_ON_LW_ERROR(dwError);
    }

    checksum.magic = KV5M_CHECKSUM;
    checksum.checksum_type = pServerSig->dwType;
    checksum.length = sServerSig;
    checksum.contents = (unsigned char *)pServerSig->pchSignature;

    ret = krb5_c_verify_checksum(
                    ctx,
                    serviceKey,
                    KRB5_KEYUSAGE_APP_DATA_CKSUM,
                    &krbPacData,
                    &checksum,
                    &bHasGoodChecksum);
    BAIL_ON_KRB_ERROR(ctx, ret);

    if (!bHasGoodChecksum)
    {
        dwError = LW_ERROR_INVALID_MESSAGE;
        BAIL_ON_LW_ERROR(dwError);
    }

    // Make sure the pac was issued with this ticket, not an old ticket
    qwNtAuthTime = pTgsTicket->enc_part2->times.authtime;
    qwNtAuthTime += 11644473600LL;
    qwNtAuthTime *= 1000*1000*10;
    if (pLogonName->ticketTime != qwNtAuthTime)
    {
        dwError = LW_ERROR_CLOCK_SKEW;
        BAIL_ON_LW_ERROR(dwError);
    }
    ret = krb5_unparse_name(
                    ctx,
                    pTgsTicket->enc_part2->client,
                    &pszClientPrincipal);
    BAIL_ON_KRB_ERROR(ctx, ret);

    // Strip off the domain name
    if (strchr(pszClientPrincipal, '@') != NULL)
    {
        strchr(pszClientPrincipal, '@')[0] = '\0'; 
    }

    dwError = LwWc16snToMbs(
        pLogonName->pwszName,
        &pszLogonName,
        pLogonName->wAccountNameLen / 2);
    BAIL_ON_LW_ERROR(dwError);    

    if (strcasecmp(pszClientPrincipal, pszLogonName))
    {
        // The pac belongs to a different user
        dwError = LW_ERROR_INVALID_LOGIN_ID;
        BAIL_ON_LW_ERROR(dwError);    
    }

    dwError = LwAllocateMemory(
                sLogonInfoLen,
                OUT_PPVOID(&pchLogonInfo));
    BAIL_ON_LW_ERROR(dwError);

    memcpy(pchLogonInfo, pchLogonInfoStart, sLogonInfoLen);
    *ppchLogonInfo = pchLogonInfo;
    *psLogonInfo = sLogonInfoLen;

cleanup:
    LW_SAFE_FREE_STRING(pszLogonName);
    LW_SAFE_FREE_MEMORY(pPacData);
    LW_SAFE_FREE_MEMORY(pchPacCopy);
    if (pszClientPrincipal != NULL)
    {
        krb5_free_unparsed_name(ctx, pszClientPrincipal);
    }
    return dwError;

error:
    LW_SAFE_FREE_MEMORY(pchLogonInfo);
    *ppchLogonInfo = NULL;
    goto cleanup;
}