Exemplo n.º 1
0
static
DWORD
UmnSrvUpdateADAccountsByHash(
    HANDLE hLsass,
    PLW_EVENTLOG_CONNECTION pEventlog,
    HANDLE hReg,
    HKEY hParameters,
    PLW_HASH_TABLE pUsers,
    long long PreviousRun,
    long long Now
    )
{
    DWORD dwError = 0;
    HKEY hUsers = NULL;
    HKEY hGroups = NULL;
    LW_HASH_ITERATOR usersIterator = { 0 };
    LW_HASH_ENTRY* pEntry = NULL;
    DWORD groupSidCount = 0;
    PSTR* ppGroupSids = NULL;
    DWORD lookupGroupSidCount = 0;
    DWORD lookupGroupSidCapacity = 0;
    // Only free the first level of this array, do not free the strings it
    // points to.
    PSTR* ppLookupGroupSids = NULL;
    LSA_QUERY_LIST list = { 0 };
    PLSA_SECURITY_OBJECT *ppLookedupGroups = NULL;
    PLW_HASH_TABLE pGroups = NULL;
    PLW_HASH_TABLE pNameToUser = NULL;
    PLW_HASH_TABLE pNameToGroup = NULL;
    DWORD i = 0;
    // Do not free
    PLSA_SECURITY_OBJECT pGroup = NULL;
    // Do not free
    PLSA_SECURITY_OBJECT pExisting = NULL;
    PSTR pNewName = NULL;

    dwError = LwHashCreate(
                    100,
                    LwHashStringCompare,
                    LwHashStringHash,
                    UmnSrvHashFreeObjectValue,
                    NULL,
                    &pGroups);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = LwHashCreate(
                    100,
                    LwHashStringCompare,
                    LwHashStringHash,
                    NULL,
                    NULL,
                    &pNameToGroup);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = LwHashCreate(
                    pUsers->sCount * 2,
                    LwHashStringCompare,
                    LwHashStringHash,
                    NULL,
                    NULL,
                    &pNameToUser);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = RegOpenKeyExA(
                hReg,
                hParameters,
                "AD Users",
                0,
                KEY_ALL_ACCESS,
                &hUsers);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = RegOpenKeyExA(
                hReg,
                hParameters,
                "AD Groups",
                0,
                KEY_ALL_ACCESS,
                &hGroups);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = LwHashGetIterator(
                    pUsers,
                    &usersIterator);
    BAIL_ON_UMN_ERROR(dwError);

    while((pEntry = LwHashNext(&usersIterator)) != NULL)
    {
        PLSA_SECURITY_OBJECT pUser = (PLSA_SECURITY_OBJECT)pEntry->pValue;

        if (gbPollerThreadShouldExit)
        {
            dwError = ERROR_CANCELLED;
            BAIL_ON_UMN_ERROR(dwError);
        }

        dwError = LwHashGetValue(
                        pNameToUser,
                        pUser->userInfo.pszUnixName,
                        (PVOID*)&pExisting);
        if (dwError != ERROR_NOT_FOUND)
        {
            BAIL_ON_UMN_ERROR(dwError);

            dwError = LwAllocateStringPrintf(
                            &pNewName,
                            "%s\\%s",
                            pUser->pszNetbiosDomainName,
                            pUser->pszSamAccountName);
            BAIL_ON_UMN_ERROR(dwError);

            UMN_LOG_ERROR("Found conflict on user name '%hhs'. Sid %hhs will now be reported as name '%s' instead because its alias conflicts with sid %hhs.",
                                    pUser->userInfo.pszUnixName,
                                    pUser->pszObjectSid,
                                    pNewName,
                                    pExisting->pszObjectSid);
            BAIL_ON_UMN_ERROR(dwError);

            LW_SAFE_FREE_STRING(pUser->userInfo.pszUnixName);
            pUser->userInfo.pszUnixName = pNewName;
            pNewName = NULL;
        }

        dwError = LwHashSetValue(
                        pNameToUser,
                        pUser->userInfo.pszUnixName,
                        pUser);
        BAIL_ON_UMN_ERROR(dwError);

        dwError = UmnSrvUpdateADUser(
                        pEventlog,
                        hReg,
                        hUsers,
                        PreviousRun,
                        Now,
                        pUser);
        if (dwError == ERROR_NO_UNICODE_TRANSLATION)
        {
            // Error message already logged
            dwError = 0;
            continue;
        }
        BAIL_ON_UMN_ERROR(dwError);

        if (ppGroupSids)
        {
            LsaFreeSidList(
                    groupSidCount,
                    ppGroupSids);
        }
        dwError = LsaQueryMemberOf(
                        hLsass,
                        NULL,
                        0,
                        1,
                        &pUser->pszObjectSid,
                        &groupSidCount,
                        &ppGroupSids);
        BAIL_ON_UMN_ERROR(dwError);

        if (groupSidCount > lookupGroupSidCapacity)
        {
            LW_SAFE_FREE_MEMORY(ppLookupGroupSids);

            dwError = LwAllocateMemory(
                            groupSidCount * sizeof(ppLookupGroupSids[0]),
                            (PVOID*)&ppLookupGroupSids);
            BAIL_ON_UMN_ERROR(dwError);

            lookupGroupSidCapacity = groupSidCount;
        }

        lookupGroupSidCount = 0;

        for (i = 0; i < groupSidCount; i++)
        {
            dwError = LwHashGetValue(
                            pGroups,
                            ppGroupSids[i],
                            (PVOID*)&pGroup);
            if (dwError == ERROR_NOT_FOUND)
            {
                ppLookupGroupSids[lookupGroupSidCount++] = ppGroupSids[i];
            }
            else
            {
                BAIL_ON_UMN_ERROR(dwError);

                UMN_LOG_VERBOSE("Found AD user %s is a member of processed group %s",
                        pUser->userInfo.pszUnixName,
                        pGroup->groupInfo.pszUnixName);

                if (!pGroup->enabled)
                {
                    UMN_LOG_VERBOSE("Skipping unenabled group %s",
                        pGroup->groupInfo.pszUnixName);
                }
                else
                {
                    dwError = UmnSrvUpdateADGroupMember(
                                    pEventlog,
                                    hReg,
                                    hGroups,
                                    PreviousRun,
                                    Now,
                                    pGroup,
                                    pUser->userInfo.pszUnixName);
                    BAIL_ON_UMN_ERROR(dwError);
                }
            }
        }
        
        if (lookupGroupSidCount)
        {
            list.ppszStrings = (PCSTR *)ppLookupGroupSids;

            dwError = LsaFindObjects(
                            hLsass,
                            NULL,
                            0,
                            LSA_OBJECT_TYPE_GROUP,
                            LSA_QUERY_TYPE_BY_SID,
                            lookupGroupSidCount,
                            list,
                            &ppLookedupGroups);
            BAIL_ON_UMN_ERROR(dwError);

            for (i = 0; i < lookupGroupSidCount; i++)
            {
                if (gbPollerThreadShouldExit)
                {
                    dwError = ERROR_CANCELLED;
                    BAIL_ON_UMN_ERROR(dwError);
                }
                pGroup = ppLookedupGroups[i];

                if (!pGroup)
                {
                    UMN_LOG_ERROR("Unable to find group sid %s that user %s is a member of",
                            ppLookupGroupSids[i],
                            pUser->userInfo.pszUnixName);
                    continue;
                }

                UMN_LOG_VERBOSE("Found AD user %s is a member of unprocessed group %s",
                        pUser->userInfo.pszUnixName,
                        pGroup->groupInfo.pszUnixName);

                dwError = LwHashGetValue(
                                pNameToGroup,
                                pGroup->groupInfo.pszUnixName,
                                (PVOID*)&pExisting);
                if (dwError != ERROR_NOT_FOUND)
                {
                    BAIL_ON_UMN_ERROR(dwError);

                    dwError = LwAllocateStringPrintf(
                                    &pNewName,
                                    "%s\\%s",
                                    pGroup->pszNetbiosDomainName,
                                    pGroup->pszSamAccountName);
                    BAIL_ON_UMN_ERROR(dwError);

                    UMN_LOG_ERROR("Found conflict on group name '%hhs'. Sid %hhs will now be reported as name '%s' instead because its alias conflicts with sid %hhs.",
                                            pGroup->groupInfo.pszUnixName,
                                            pGroup->pszObjectSid,
                                            pNewName,
                                            pExisting->pszObjectSid);
                    BAIL_ON_UMN_ERROR(dwError);

                    LW_SAFE_FREE_STRING(pGroup->groupInfo.pszUnixName);
                    pGroup->groupInfo.pszUnixName = pNewName;
                    pNewName = NULL;
                }

                dwError = LwHashSetValue(
                                pNameToGroup,
                                pGroup->groupInfo.pszUnixName,
                                pGroup);
                BAIL_ON_UMN_ERROR(dwError);

                if (!pGroup->enabled)
                {
                    UMN_LOG_VERBOSE("Skipping unenabled group %s",
                        pGroup->groupInfo.pszUnixName);
                }
                else
                {
                    dwError = UmnSrvUpdateADGroup(
                                    pEventlog,
                                    hReg,
                                    hGroups,
                                    PreviousRun,
                                    Now,
                                    pGroup);
                    BAIL_ON_UMN_ERROR(dwError);

                    dwError = UmnSrvUpdateADGroupMember(
                                    pEventlog,
                                    hReg,
                                    hGroups,
                                    PreviousRun,
                                    Now,
                                    pGroup,
                                    pUser->userInfo.pszUnixName);
                    BAIL_ON_UMN_ERROR(dwError);
                }
                dwError = LwHashSetValue(
                                pGroups,
                                pGroup->pszObjectSid,
                                pGroup);
                BAIL_ON_UMN_ERROR(dwError);

                ppLookedupGroups[i] = NULL;
            }

            LsaFreeSecurityObjectList(
                lookupGroupSidCount,
                ppLookedupGroups);
            ppLookedupGroups = NULL;
        }
    }

    dwError = UmnSrvFindDeletedUsers(
                    pEventlog,
                    hReg,
                    "AD Users",
                    hUsers,
                    Now);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = UmnSrvFindDeletedGroups(
                    pEventlog,
                    hReg,
                    "AD Groups",
                    hGroups,
                    Now);
    BAIL_ON_UMN_ERROR(dwError);

cleanup:
    LW_SAFE_FREE_STRING(pNewName);
    LW_SAFE_FREE_MEMORY(ppLookupGroupSids);
    if (ppGroupSids)
    {
        LsaFreeSidList(
                groupSidCount,
                ppGroupSids);
    }
    if (ppLookedupGroups)
    {
        LsaFreeSecurityObjectList(
            lookupGroupSidCount,
            ppLookedupGroups);
    }
    if (hUsers)
    {
        RegCloseKey(hReg, hUsers);
    }
    if (hGroups)
    {
        RegCloseKey(hReg, hGroups);
    }
    LwHashSafeFree(&pGroups);
    LwHashSafeFree(&pNameToUser);
    LwHashSafeFree(&pNameToGroup);
    return dwError;
    
error:
    goto cleanup;
}
Exemplo n.º 2
0
DWORD
UmnEvtGetFQDN(
    char *pszFQDNHostname, 
    size_t len) 
{
    DWORD dwError = 0;
    char pszHostname[1024];

    const struct addrinfo hints = {
        .ai_flags = AI_CANONNAME | AI_ADDRCONFIG,
        .ai_family = AF_UNSPEC,
        .ai_socktype = 0,
        .ai_protocol = 0,
        .ai_canonname = NULL,
        .ai_addr = NULL,
        .ai_next = NULL
    };

    struct addrinfo *paddrs= NULL;
    struct addrinfo *paddr = NULL;

    dwError = gethostname(pszHostname, sizeof(pszHostname)); 
    if (dwError) 
    {
        goto error;
    }

    dwError = getaddrinfo(pszHostname, NULL, &hints, &paddrs);
    if (dwError) 
    {
        UMN_LOG_ERROR("Failed obtaining fully qualified domain name getaddrinfo: %s\n", gai_strerror(dwError));
        goto error;
    }

    for(paddr = paddrs; paddr != NULL; paddr = paddrs->ai_next) {
        if (paddr->ai_canonname) {
            strncpy(pszFQDNHostname, paddr->ai_canonname, len - 1);
            if (len > 0 ) {
                pszFQDNHostname[len - 1] = '\0';
            }

            if (strlen(pszFQDNHostname) < strlen(paddr->ai_canonname)) {
                dwError = ENAMETOOLONG;
            }
            
            break;
        }
    }

cleanup:
    if (paddrs) {
        freeaddrinfo(paddrs);
    }

    return dwError;

error:
    goto cleanup;
}


DWORD 
UmnEvtSetEventComputerName(
    const char *pszEventComputerName) 
{
    DWORD dwError = LW_ERROR_SUCCESS;
    char pszComputerName[1024] = {0};

    strncpy(pszComputerName, pszEventComputerName, sizeof(pszComputerName) - 1);
    pszComputerName[sizeof(pszComputerName) - 1] = '\0';

    BOOLEAN isTruncated = (strlen(pszComputerName) < strlen(pszEventComputerName));
    dwError = LwMbsToWc16s(pszComputerName, &gEventComputerName);

    return (dwError 
            ? dwError 
            : ((isTruncated) 
                ? LW_ERROR_ERRNO_ENAMETOOLONG  
                : LW_ERROR_SUCCESS));
}
Exemplo n.º 3
0
static
DWORD
UmnSrvUpdateADUser(
    PLW_EVENTLOG_CONNECTION pEventlog,
    HANDLE hReg,
    HKEY hUsers,
    long long PreviousRun,
    long long Now,
    PLSA_SECURITY_OBJECT pUser
    )
{
    DWORD dwError = 0;
    HKEY hKey = NULL;
    USER_MONITOR_PASSWD old = { 0 };
    DWORD dwNow = Now;
    PSTR pEncodedUser = NULL;

    dwError = LwURLEncodeString(
                    pUser->userInfo.pszUnixName,
                    &pEncodedUser);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = RegOpenKeyExA(
                    hReg,
                    hUsers,
                    pEncodedUser,
                    0,
                    KEY_ALL_ACCESS,
                    &hKey);
    if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE)
    {
        UMN_LOG_INFO("Adding user '%s' (uid %d)",
                        pUser->userInfo.pszUnixName, pUser->userInfo.uid);

        dwError = RegCreateKeyExA(
                        hReg,
                        hUsers,
                        pEncodedUser,
                        0,
                        NULL,
                        0,
                        KEY_ALL_ACCESS,
                        NULL,
                        &hKey,
                        NULL);
        BAIL_ON_UMN_ERROR(dwError);

        dwError = UmnSrvWriteADUserValues(
                        hReg,
                        hKey,
                        pUser);
        if (dwError == ERROR_NO_UNICODE_TRANSLATION)
        {
            UMN_LOG_ERROR("Ignoring user with URL encoding %s because one of their fields has no UCS-2 representation", pEncodedUser);

            // Delete the key so it does not show up with blank values next
            // time.
            dwError = RegCloseKey(
                    hReg,
                    hKey);
            BAIL_ON_UMN_ERROR(dwError);
            hKey = NULL;

            dwError = RegDeleteKeyA(
                            hReg,
                            hUsers,
                            pEncodedUser);
            BAIL_ON_UMN_ERROR(dwError);

            dwError = ERROR_NO_UNICODE_TRANSLATION;
            BAIL_ON_UMN_ERROR(dwError);
        }
        BAIL_ON_UMN_ERROR(dwError);

        dwError = UmnSrvWriteADUserEvent(
                        pEventlog,
                        PreviousRun,
                        NULL,
                        Now,
                        pUser);
        BAIL_ON_UMN_ERROR(dwError);
    }
    else
    {
        BAIL_ON_UMN_ERROR(dwError);

        dwError = UmnSrvReadUser(
                        "AD Users",
                        pEncodedUser,
                        &old);
        BAIL_ON_UMN_ERROR(dwError);

        if (strcmp((pUser->userInfo.pszPasswd ?
                        pUser->userInfo.pszPasswd : "x"),
                    old.pw_passwd) ||
                pUser->userInfo.uid != old.pw_uid ||
                pUser->userInfo.gid != old.pw_gid ||
                !UmnSrvStringsEqual(pUser->userInfo.pszGecos, old.pw_gecos) ||
                !UmnSrvStringsEqual(pUser->userInfo.pszHomedir, old.pw_dir) ||
                !UmnSrvStringsEqual(pUser->userInfo.pszShell, old.pw_shell) ||
                !UmnSrvStringsEqual(pUser->userInfo.pszDisplayName,
                    old.pDisplayName))
        {
            UMN_LOG_INFO("User '%s' (uid %d) changed",
                            pUser->userInfo.pszUnixName, pUser->userInfo.uid);
            dwError = UmnSrvWriteADUserValues(
                            hReg,
                            hKey,
                            pUser);
            BAIL_ON_UMN_ERROR(dwError);

            dwError = UmnSrvWriteADUserEvent(
                            pEventlog,
                            PreviousRun,
                            &old,
                            Now,
                            pUser);
            BAIL_ON_UMN_ERROR(dwError);
        }
    }

    dwError = RegSetValueExA(
                    hReg,
                    hKey,
                    "LastUpdated",
                    0,
                    REG_DWORD,
                    (PBYTE)&dwNow,
                    sizeof(dwNow));
    BAIL_ON_UMN_ERROR(dwError);

cleanup:
    LW_SAFE_FREE_STRING(pEncodedUser);
    UmnSrvFreeUserContents(&old);
    if (hKey)
    {
        RegCloseKey(
                hReg,
                hKey);
    }
    return dwError;
    
error:
    goto cleanup;
}
Exemplo n.º 4
0
PVOID
UmnSrvPollerThreadRoutine(
    IN PVOID pUnused
    )
{
    DWORD dwError = 0;

    struct timeval now;
    struct timespec periodStart, periodUsed, nextWake, pushWait = {0};
    DWORD dwPeriodSecs = 0;
    
    char regErrMsg[256] = {0};
    char fqdn[1024] = {0};

    BOOLEAN bMutexLocked = FALSE;

    UMN_LOG_INFO("User poller thread started");
    dwError = pthread_mutex_lock(&gSignalPollerMutex);
    BAIL_ON_UMN_ERROR(dwError);
    bMutexLocked = TRUE;

    dwError = UmnSrvNow(&periodStart, &now);
    BAIL_ON_UMN_ERROR(dwError);

    while (!gbPollerThreadShouldExit)
    {
        dwError = UmnSrvGetCheckInterval(&dwPeriodSecs);
        BAIL_ON_UMN_ERROR(dwError);
        pushWait.tv_sec = dwPeriodSecs;

        UmnSrvTimespecAdd(
            &nextWake,
            &periodStart,
            &pushWait);

        UMN_LOG_INFO("User poller sleeping for %f seconds",
                pushWait.tv_sec + pushWait.tv_nsec /
                (double)NANOSECS_PER_SECOND);

        while (!gbPollerThreadShouldExit && !gbPollerRefresh)
        {
            BOOLEAN bWaitElapsed = FALSE;

            dwError = pthread_cond_timedwait(
                        &gSignalPoller,
                        &gSignalPollerMutex,
                        &nextWake);

            if (dwError == EINTR)
            {
                UMN_LOG_DEBUG("User poller cond wait interrupted; continuing.");
                continue;
            }

            if (dwError == ETIMEDOUT)
            {
                UMN_LOG_DEBUG("User poller cond wait completed.");
                dwError = 0;
                break;
            }

            if (dwError != 0) 
            {
                UMN_LOG_ERROR("Timed wait error: error %s (%d).", 
                      ErrnoToName(dwError), dwError);
                BAIL_ON_UMN_ERROR(dwError);
            }

            dwError = UmnSrvTimespecElapsed(&nextWake, &bWaitElapsed);
            if (dwError == 0 && bWaitElapsed == TRUE) 
            {
                break;
            }
        }

        gbPollerRefresh = FALSE;

        if (!gbPollerThreadShouldExit)
        {
            dwError = UmnSrvNow(&periodStart, &now);
            BAIL_ON_UMN_ERROR(dwError);

            // obtain the fully qualified domain name and use it throughout this iteration
            UmnEvtFreeEventComputerName();
            UmnEvtGetFQDN(fqdn, sizeof(fqdn));
            UmnEvtSetEventComputerName(fqdn);

            dwError = UmnSrvUpdateAccountInfo(now.tv_sec);
            if (dwError == ERROR_CANCELLED)
            {
                UMN_LOG_INFO("User poller cancelled iteration");
                dwError = 0;
                break;
            }

            // simply log other errors and attempt to continue
            if (dwError != LW_ERROR_SUCCESS) 
            {
                if (LwRegIsRegistrySpecificError(dwError))
                {
                    LwRegGetErrorString(dwError, regErrMsg, sizeof(regErrMsg) - 1);
                    UMN_LOG_ERROR("Failed updating account info, registry error = %d  %s. Continuing.",
                            dwError, regErrMsg);
                }
                else 
                {
                    UMN_LOG_ERROR("Failed updating account info, error = %d symbol = %s %s. Continuing.", 
                        dwError,
                        LwWin32ExtErrorToName(dwError), 
                        LwWin32ExtErrorToDescription(dwError));
                }
                dwError = 0;
            }

            // periodUsed = now - periodStart
            dwError = UmnSrvNow(&periodUsed, &now);
            BAIL_ON_UMN_ERROR(dwError);

            UmnSrvTimespecSubtract(
                &periodUsed,
                &periodUsed,
                &periodStart);

            UMN_LOG_DEBUG("Account activity update took %f seconds",
                    periodUsed.tv_sec + periodUsed.tv_nsec /
                    (double)NANOSECS_PER_SECOND);
        }
    }

    UMN_LOG_INFO("User poller thread stopped");

cleanup:
    if (bMutexLocked)
    {
        pthread_mutex_unlock(&gSignalPollerMutex);
    }

    if (dwError != 0)
    {
        UMN_LOG_ERROR(
                "User monitor polling thread exiting with code %d",
                dwError);
        kill(getpid(), SIGTERM);
    }

    return NULL;

error:
    goto cleanup;
}