Beispiel #1
0
DWORD
LocalDirFindObjectByGenericName(
    HANDLE hProvider,
    IN LSA_FIND_FLAGS FindFlags,
    IN LSA_OBJECT_TYPE ObjectType,
    PCSTR pszName,
    PLSA_SECURITY_OBJECT* ppObject
    )
{
    DWORD dwError = 0;
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
    LSA_QUERY_LIST QueryList;
    LSA_QUERY_TYPE QueryType = 0;
    PLSA_LOGIN_NAME_INFO pLoginInfo = NULL;

    BAIL_ON_INVALID_HANDLE(hProvider);

    dwError = LsaSrvCrackDomainQualifiedName(
        pszName,
        &pLoginInfo);
    BAIL_ON_LSA_ERROR(dwError);

    switch (pLoginInfo->nameType)
    {
    case NameType_NT4:
        QueryType = LSA_QUERY_TYPE_BY_NT4;
        break;
    case NameType_UPN:
        QueryType = LSA_QUERY_TYPE_BY_UPN;
        break;
    case NameType_Alias:
        QueryType = LSA_QUERY_TYPE_BY_ALIAS;
        break;
    default:
        dwError = LW_ERROR_INTERNAL;
        BAIL_ON_LSA_ERROR(dwError);
    }

    QueryList.ppszStrings = &pszName;

    dwError = LocalFindObjects(
        hProvider,
        FindFlags,
        ObjectType,
        QueryType,
        1,
        QueryList,
        &ppObjects);
    BAIL_ON_LSA_ERROR(dwError);

    if (ppObjects[0] == NULL)
    {
        switch (ObjectType)
        {
        case LSA_OBJECT_TYPE_USER:
            dwError = LW_ERROR_NO_SUCH_USER;
            break;
        case LSA_OBJECT_TYPE_GROUP:
            dwError = LW_ERROR_NO_SUCH_GROUP;
            break;
        default:
            dwError = LW_ERROR_NO_SUCH_OBJECT;
        }
        BAIL_ON_LSA_ERROR(dwError);
    }
    
    *ppObject = ppObjects[0];
    ppObjects[0] = NULL;

cleanup:

    if (pLoginInfo)
    {
        LsaSrvFreeNameInfo(pLoginInfo);
    }

    LsaUtilFreeSecurityObjectList(1, ppObjects);

    return dwError;

error:

    goto cleanup;
}
Beispiel #2
0
static
DWORD
LocalDirFindObjectsInternal(
    IN HANDLE hProvider,
    IN LSA_FIND_FLAGS FindFlags,
    IN OPTIONAL LSA_OBJECT_TYPE ObjectType,
    IN LSA_QUERY_TYPE QueryType,
    IN DWORD dwCount,
    IN LSA_QUERY_LIST QueryList,
    IN OUT PLSA_SECURITY_OBJECT* ppObjects
    )
{
    DWORD dwError = 0;
    PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider;
    static WCHAR wszAttrNameObjectClass[]    = LOCAL_DIR_ATTR_OBJECT_CLASS;
    static WCHAR wszAttrNameUID[]            = LOCAL_DIR_ATTR_UID;
    static WCHAR wszAttrNameGID[]            = LOCAL_DIR_ATTR_GID;
    static WCHAR wszAttrNamePrimaryGroup[]   = LOCAL_DIR_ATTR_PRIMARY_GROUP;
    static WCHAR wszAttrNameSamAccountName[] = LOCAL_DIR_ATTR_SAM_ACCOUNT_NAME;
    static WCHAR wszAttrNamePassword[]       = LOCAL_DIR_ATTR_PASSWORD;
    static WCHAR wszAttrNameGecos[]          = LOCAL_DIR_ATTR_GECOS;
    static WCHAR wszAttrNameShell[]          = LOCAL_DIR_ATTR_SHELL;
    static WCHAR wszAttrNameHomedir[]        = LOCAL_DIR_ATTR_HOME_DIR;
    static WCHAR wszAttrNameUPN[]            = LOCAL_DIR_ATTR_USER_PRINCIPAL_NAME;
    static WCHAR wszAttrNameObjectSID[]      = LOCAL_DIR_ATTR_OBJECT_SID;
    static WCHAR wszAttrNameDN[]             = LOCAL_DIR_ATTR_DISTINGUISHED_NAME;
    static WCHAR wszAttrNameNetBIOSDomain[]  = LOCAL_DIR_ATTR_NETBIOS_NAME;
    static WCHAR wszAttrNameUserInfoFlags[]  = LOCAL_DIR_ATTR_ACCOUNT_FLAGS;
    static WCHAR wszAttrNameAccountExpiry[]  = LOCAL_DIR_ATTR_ACCOUNT_EXPIRY;
    static WCHAR wszAttrNamePasswdLastSet[]  = LOCAL_DIR_ATTR_PASSWORD_LAST_SET;
    static WCHAR wszAttrNameNTHash[]         = LOCAL_DIR_ATTR_NT_HASH;
    static WCHAR wszAttrNameLMHash[]         = LOCAL_DIR_ATTR_LM_HASH;
    static PWSTR wszAttrs[] =
    {
        wszAttrNameObjectClass,
        wszAttrNameUID,
        wszAttrNameGID,
        wszAttrNamePrimaryGroup,
        wszAttrNameSamAccountName,
        wszAttrNamePassword,
        wszAttrNameGecos,
        wszAttrNameShell,
        wszAttrNameHomedir,
        wszAttrNameUPN,
        wszAttrNameObjectSID,
        wszAttrNameDN,
        wszAttrNameNetBIOSDomain,
        wszAttrNameUserInfoFlags,
        wszAttrNameAccountExpiry,
        wszAttrNamePasswdLastSet,
        wszAttrNameNTHash,
        wszAttrNameLMHash,
        NULL
    };
    PDIRECTORY_ENTRY pEntries = NULL;
    PDIRECTORY_ENTRY pEntry = NULL;
    DWORD dwNumEntries = 0;
    PCSTR pszFilterTemplateQualified = 
        LOCAL_DB_DIR_ATTR_NETBIOS_NAME " = %Q" \
        " AND " LOCAL_DB_DIR_ATTR_SAM_ACCOUNT_NAME " = %Q%s";
    PCSTR pszFilterTemplateString = "%s = %Q%s";
    PCSTR pszFilterTemplateDword = "%s = %u%s";
    PCSTR pszFilterTemplateType = " AND " LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u";
    PCSTR pszFilterTemplateUserOrGroup = " AND (" \
            LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u OR " \
            LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u)";
    PCSTR pszFilterBy = NULL;
    PSTR pszFilterType = NULL;
    PWSTR pwszFilter = NULL;
    DWORD dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN;
    DWORD dwIndex = 0;
    PLSA_LOGIN_NAME_INFO pLoginInfo = NULL;
    BOOLEAN bLocked = FALSE;
    BOOLEAN bFoundInvalidObject = FALSE;

    /* FIXME: support generic queries */
    switch (ObjectType)
    {
    case LSA_OBJECT_TYPE_UNDEFINED:
        dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN;
        break;
    case LSA_OBJECT_TYPE_USER:
        dwObjectClass = LOCAL_OBJECT_CLASS_USER;
        break;
    case LSA_OBJECT_TYPE_GROUP:
        dwObjectClass = LOCAL_OBJECT_CLASS_GROUP;
        break;
    default:
        dwError = LW_ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    switch (QueryType)
    {
    case LSA_QUERY_TYPE_BY_DN:
        pszFilterBy = LOCAL_DB_DIR_ATTR_DISTINGUISHED_NAME;
        break;
    case LSA_QUERY_TYPE_BY_SID:
        pszFilterBy = LOCAL_DB_DIR_ATTR_OBJECT_SID;
        break;
    case LSA_QUERY_TYPE_BY_NT4:
    case LSA_QUERY_TYPE_BY_ALIAS:
        break;
    case LSA_QUERY_TYPE_BY_UPN:
        pszFilterBy = LOCAL_DB_DIR_ATTR_USER_PRINCIPAL_NAME;
        break;
    case LSA_QUERY_TYPE_BY_UNIX_ID:
        if (dwObjectClass == LOCAL_OBJECT_CLASS_USER)
        {
            pszFilterBy = LOCAL_DB_DIR_ATTR_UID;
        }
        else
        {
            pszFilterBy = LOCAL_DB_DIR_ATTR_GID;
        }
        break;
    default:
        dwError = LW_ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (dwObjectClass == LOCAL_OBJECT_CLASS_UNKNOWN)
    {
        dwError = LwAllocateStringPrintf(
            &pszFilterType,
            pszFilterTemplateUserOrGroup,
            LOCAL_OBJECT_CLASS_USER,
            LOCAL_OBJECT_CLASS_GROUP);
        BAIL_ON_LSA_ERROR(dwError);
    }
    else
    {
        dwError = LwAllocateStringPrintf(
            &pszFilterType,
            pszFilterTemplateType,
            dwObjectClass);
        BAIL_ON_LSA_ERROR(dwError);
    }

    for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
    {
        bFoundInvalidObject = FALSE;

        switch (QueryType)
        {
        case LSA_QUERY_TYPE_BY_ALIAS:
        case LSA_QUERY_TYPE_BY_NT4:
            dwError = LsaSrvCrackDomainQualifiedName(
                QueryList.ppszStrings[dwIndex],
                &pLoginInfo);
            BAIL_ON_LSA_ERROR(dwError);

            if (!pLoginInfo->pszDomain)
            {
                LOCAL_RDLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock);

                dwError = LwAllocateString(
                                gLPGlobals.pszNetBIOSName,
                                &pLoginInfo->pszDomain);
                BAIL_ON_LSA_ERROR(dwError);

                LOCAL_UNLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock);
            }

            dwError = DirectoryAllocateWC16StringFilterPrintf(
                &pwszFilter,
                pszFilterTemplateQualified,
                pLoginInfo->pszDomain,
                pLoginInfo->pszName,
                pszFilterType ? pszFilterType : "");
            BAIL_ON_LSA_ERROR(dwError);
            break;

        case LSA_QUERY_TYPE_BY_DN:
        case LSA_QUERY_TYPE_BY_SID:
        case LSA_QUERY_TYPE_BY_UPN:
            dwError = DirectoryAllocateWC16StringFilterPrintf(
                &pwszFilter,
                pszFilterTemplateString,
                pszFilterBy,
                QueryList.ppszStrings[dwIndex],
                pszFilterType ? pszFilterType : "");
            BAIL_ON_LSA_ERROR(dwError);
            break;

        case LSA_QUERY_TYPE_BY_UNIX_ID:
            dwError = DirectoryAllocateWC16StringFilterPrintf(
                &pwszFilter,
                pszFilterTemplateDword,
                pszFilterBy,
                QueryList.pdwIds[dwIndex],
                pszFilterType ? pszFilterType : "");
            BAIL_ON_LSA_ERROR(dwError);
            break;
        default:
            dwError = LW_ERROR_INVALID_PARAMETER;
            BAIL_ON_LSA_ERROR(dwError);
        }
        
        dwError = DirectorySearch(
            pContext->hDirectory,
            NULL,
            0,
            pwszFilter,
            wszAttrs,
            FALSE,
            &pEntries,
            &dwNumEntries);
        BAIL_ON_LSA_ERROR(dwError);
        
        if (dwNumEntries > 1)
        {
            dwError = LW_ERROR_DATA_ERROR;
            BAIL_ON_LSA_ERROR(dwError);
        }
        else if (dwNumEntries == 1)
        {
            pEntry = &pEntries[0];
            
            dwError = LocalMarshalEntryToSecurityObject(
                pEntry,
                &ppObjects[dwIndex]);
            if (dwError)
            {
                if (dwError == LW_ERROR_NO_SUCH_OBJECT)
                {
                    bFoundInvalidObject = TRUE;
                    dwError = 0;
                }
                else
                {
                    BAIL_ON_LSA_ERROR(dwError);
                }
            }
            else
            {
                dwError = LocalDirResolveUserObjectPrimaryGroupSid(
                    hProvider,
                    ppObjects[dwIndex]);
                BAIL_ON_LSA_ERROR(dwError);
            }
        }

        if ((dwNumEntries == 0 || bFoundInvalidObject) && QueryType == LSA_QUERY_TYPE_BY_UPN)
        {
            /* UPN lookup might fail because the UPN is generated, so try
               again as an NT4 lookup */
            LSA_QUERY_LIST Single;

            Single.ppszStrings = &QueryList.ppszStrings[dwIndex];
            
            dwError = LocalDirFindObjectsInternal(
                hProvider,
                FindFlags,
                ObjectType,
                LSA_QUERY_TYPE_BY_NT4,
                1,
                Single,
                &ppObjects[dwIndex]);
            BAIL_ON_LSA_ERROR(dwError);
        }

        LW_SAFE_FREE_MEMORY(pwszFilter);

        if (pEntries)
        {
            DirectoryFreeEntries(pEntries, dwNumEntries);
            pEntries = NULL;
        }

        if (pLoginInfo)
        {
            LsaSrvFreeNameInfo(pLoginInfo);
            pLoginInfo = NULL;
        }
    }

cleanup:
    LOCAL_UNLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock);
    LW_SAFE_FREE_STRING(pszFilterType);
    LW_SAFE_FREE_MEMORY(pwszFilter);

    if (pEntries)
    {
        DirectoryFreeEntries(pEntries, dwNumEntries);
    }

    if (pLoginInfo)
    {
        LsaSrvFreeNameInfo(pLoginInfo);
    }

    return dwError;

error:

    goto cleanup;
}
Beispiel #3
0
DWORD
NtlmCreateResponseContext(
    IN PNTLM_CHALLENGE_MESSAGE pChlngMsg,
    IN NTLM_CRED_HANDLE hCred,
    IN BOOLEAN bDoAnonymous,
    OUT PNTLM_CONTEXT* ppNtlmContext,
    OUT PSecBuffer pOutput
)
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PNTLM_RESPONSE_MESSAGE_V1 pMessage = NULL;
    PCSTR pUserNameTemp = NULL;
    PCSTR pPassword = NULL;
    PNTLM_CONTEXT pNtlmContext = NULL;
    PBYTE pMasterKey = NULL;
    BYTE LmUserSessionKey[NTLM_SESSION_KEY_SIZE] = {0};
    BYTE NtlmUserSessionKey[NTLM_SESSION_KEY_SIZE] = {0};
    BYTE LanManagerSessionKey[NTLM_SESSION_KEY_SIZE] = {0};
    BYTE SecondaryKey[NTLM_SESSION_KEY_SIZE] = {0};
    PLSA_LOGIN_NAME_INFO pUserNameInfo = NULL;
    DWORD dwMessageSize = 0;
    NTLM_CONFIG config;
    DWORD dwNtRespType = 0;
    DWORD dwLmRespType = 0;

    *ppNtlmContext = NULL;

    dwError = NtlmReadRegistry(&config);
    BAIL_ON_LSA_ERROR(dwError);

    if (bDoAnonymous)
    {
        pUserNameTemp = "";
        pPassword = "";
    }
    else
    {
        NtlmGetCredentialInfo(
            hCred,
            &pUserNameTemp,
            &pPassword,
            NULL);

        if (!pUserNameTemp[0] && !pPassword[0])
        {
            bDoAnonymous = TRUE;
        }
    }

    if (bDoAnonymous)
    {
        dwError = LwAllocateMemory(
                      sizeof(*pUserNameInfo),
                      OUT_PPVOID(&pUserNameInfo));
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateString(
                      "",
                      &pUserNameInfo->pszName);
        BAIL_ON_LSA_ERROR(dwError);
        dwError = LwAllocateString(
                      "",
                      &pUserNameInfo->pszDomain);
        BAIL_ON_LSA_ERROR(dwError);
    }
    else
    {
        dwError = LsaSrvCrackDomainQualifiedName(
                      pUserNameTemp,
                      &pUserNameInfo);
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = NtlmCreateContext(hCred, &pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwAllocateString(
                  pUserNameTemp,
                  &pNtlmContext->pszClientUsername);
    BAIL_ON_LSA_ERROR(dwError);

    if (bDoAnonymous)
    {
        dwNtRespType = NTLM_RESPONSE_TYPE_ANON_NTLM;
        dwLmRespType = NTLM_RESPONSE_TYPE_ANON_LM;
    }
    else if (config.bSendNTLMv2)
    {
        dwNtRespType = NTLM_RESPONSE_TYPE_NTLMv2;
        // TODO: the correct thing is to use LMv2
        dwLmRespType = NTLM_RESPONSE_TYPE_LM;
    }
    else if(LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_NTLM2)
    {
        dwLmRespType = NTLM_RESPONSE_TYPE_NTLM2;
        dwNtRespType = NTLM_RESPONSE_TYPE_NTLM2;
    }
    else
    {
        dwNtRespType = NTLM_RESPONSE_TYPE_NTLM;
        dwLmRespType = NTLM_RESPONSE_TYPE_LM;
    }

    dwError = NtlmCreateResponseMessage(
                  pChlngMsg,
                  pUserNameInfo->pszName,
                  pUserNameInfo->pszDomain,
                  pPassword,
                  (PBYTE)&gXpSpoof,
                  dwNtRespType,
                  dwLmRespType,
                  &dwMessageSize,
                  &pMessage,
                  LmUserSessionKey,
                  NtlmUserSessionKey
              );
    BAIL_ON_LSA_ERROR(dwError);

    // As a side effect of creating the response, we must also set/produce the
    // master session key...

    pMasterKey = NtlmUserSessionKey;

    if (LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_LM_KEY)
    {
        NtlmGenerateLanManagerSessionKey(
            pMessage,
            LmUserSessionKey,
            LanManagerSessionKey);

        pMasterKey = LanManagerSessionKey;
    }

    if (LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_KEY_EXCH)
    {
        // This is the key we will use for session security...
        dwError = NtlmGetRandomBuffer(
                      SecondaryKey,
                      NTLM_SESSION_KEY_SIZE);
        BAIL_ON_LSA_ERROR(dwError);

        // Encrypt it with the "master key" set above and send it along with the
        // response
        NtlmStoreSecondaryKey(
            pMasterKey,
            SecondaryKey,
            pMessage);

        pMasterKey = SecondaryKey;
    }

    NtlmWeakenSessionKey(
        pChlngMsg,
        pMasterKey,
        &pNtlmContext->cbSessionKeyLen);

    memcpy(pNtlmContext->SessionKey, pMasterKey, NTLM_SESSION_KEY_SIZE);

    pNtlmContext->NegotiatedFlags = LW_LTOH32(pChlngMsg->NtlmFlags);
    pOutput->cbBuffer = dwMessageSize;
    pOutput->BufferType = SECBUFFER_TOKEN;
    pOutput->pvBuffer = pMessage;
    pNtlmContext->NtlmState = NtlmStateResponse;
    pNtlmContext->bInitiatedSide = TRUE;
    pNtlmContext->bDoAnonymous = bDoAnonymous;

    dwError = NtlmInitializeKeys(pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

cleanup:
    if (pUserNameInfo)
    {
        LsaSrvFreeNameInfo(pUserNameInfo);
    }

    *ppNtlmContext = pNtlmContext;

    return dwError;
error:
    LW_SAFE_FREE_MEMORY(pMessage);
    if (pNtlmContext)
    {
        NtlmFreeContext(&pNtlmContext);
    }
    pOutput->cbBuffer = 0;
    pOutput->BufferType = 0;
    pOutput->pvBuffer = NULL;

    goto cleanup;
}