static DWORD UmnSrvUpdateUser( PLW_EVENTLOG_CONNECTION pEventlog, HANDLE hReg, HKEY hUsers, long long PreviousRun, long long Now, struct passwd *pUser ) { DWORD dwError = 0; HKEY hKey = NULL; USER_MONITOR_PASSWD old = { 0 }; DWORD dwNow = Now; PSTR pEncodedUser = NULL; dwError = LwURLEncodeString( pUser->pw_name, &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->pw_name, pUser->pw_uid); dwError = RegCreateKeyExA( hReg, hUsers, pEncodedUser, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteUserValues( hReg, hKey, pUser); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteUserEvent( pEventlog, PreviousRun, NULL, Now, pUser); BAIL_ON_UMN_ERROR(dwError); } else { BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvReadUser( "Users", pEncodedUser, &old); BAIL_ON_UMN_ERROR(dwError); if (strcmp(pUser->pw_name, old.pw_name) || strcmp(pUser->pw_passwd, old.pw_passwd) || pUser->pw_uid != old.pw_uid || pUser->pw_gid != old.pw_gid || strcmp(pUser->pw_gecos, old.pw_gecos) || strcmp(pUser->pw_dir, old.pw_dir) || strcmp(pUser->pw_shell, old.pw_shell)) { UMN_LOG_INFO("User '%s' (uid %d) changed", pUser->pw_name, pUser->pw_uid); dwError = UmnSrvWriteUserValues( hReg, hKey, pUser); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteUserEvent( 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; }
DWORD UmnSrvUpdateADGroupMember( PLW_EVENTLOG_CONNECTION pEventlog, HANDLE hReg, HKEY hGroups, long long PreviousRun, long long Now, PLSA_SECURITY_OBJECT pGroup, PCSTR pMember ) { DWORD dwError = 0; HKEY hKey = NULL; HKEY hMembers = NULL; DWORD dwNow = Now; PSTR pEncodedMember = NULL; PSTR pKeyName = NULL; PSTR pEncodedGroup = NULL; PSTR pMembersKeyName = NULL; dwError = LwURLEncodeString( pMember, &pEncodedMember); BAIL_ON_UMN_ERROR(dwError); dwError = LwURLEncodeString( pGroup->groupInfo.pszUnixName, &pEncodedGroup); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateStringPrintf( &pKeyName, "%s\\Members\\%s", pEncodedGroup, pEncodedMember); BAIL_ON_UMN_ERROR(dwError); dwError = RegOpenKeyExA( hReg, hGroups, pKeyName, 0, KEY_ALL_ACCESS, &hKey); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { UMN_LOG_INFO("Adding user member '%s' to group '%s' (gid %d)", pMember, pGroup->groupInfo.pszUnixName, pGroup->groupInfo.gid); dwError = LwAllocateStringPrintf( &pMembersKeyName, "%s\\Members", pEncodedGroup); BAIL_ON_UMN_ERROR(dwError); dwError = RegOpenKeyExA( hReg, hGroups, pMembersKeyName, 0, KEY_ALL_ACCESS, &hMembers); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { // Previous run left registry in inconsistent state dwError = RegCreateKeyExA( hReg, hGroups, pMembersKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hMembers, NULL); BAIL_ON_UMN_ERROR(dwError); } BAIL_ON_UMN_ERROR(dwError); dwError = RegCreateKeyExA( hReg, hMembers, pEncodedMember, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteGroupMemberEvent( pEventlog, Now, "AD Groups", PreviousRun, TRUE, //Add member FALSE, //Not gid change pMember, pGroup->groupInfo.gid, pGroup->groupInfo.pszUnixName); 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(pEncodedGroup); LW_SAFE_FREE_STRING(pKeyName); LW_SAFE_FREE_STRING(pMembersKeyName); LW_SAFE_FREE_STRING(pEncodedMember); if (hKey) { RegCloseKey( hReg, hKey); } if (hMembers) { RegCloseKey( hReg, hMembers); } return dwError; error: goto cleanup; }
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; }
DWORD UmnSrvUpdateADGroup( PLW_EVENTLOG_CONNECTION pEventlog, HANDLE hReg, HKEY hGroups, long long PreviousRun, long long Now, PLSA_SECURITY_OBJECT pGroup ) { DWORD dwError = 0; HKEY hKey = NULL; HKEY hMembers = NULL; USER_MONITOR_GROUP old = { 0 }; DWORD dwNow = Now; old.gr_gid = -1; PSTR pEncodedGroup = NULL; dwError = LwURLEncodeString( pGroup->groupInfo.pszUnixName, &pEncodedGroup); BAIL_ON_UMN_ERROR(dwError); dwError = RegOpenKeyExA( hReg, hGroups, pEncodedGroup, 0, KEY_ALL_ACCESS, &hKey); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { dwError = 0; } else { BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvReadGroup( "AD Groups", pEncodedGroup, &old); BAIL_ON_UMN_ERROR(dwError); } // Check if the key does not exist yet, or it was not fully populated. if (old.LastUpdated == 0) { UMN_LOG_INFO("Adding group '%s' (gid %d)", pGroup->groupInfo.pszUnixName, pGroup->groupInfo.gid); dwError = RegCreateKeyExA( hReg, hGroups, pEncodedGroup, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL); if (dwError == LWREG_ERROR_KEYNAME_EXIST) { // The key exists, but the values were not fully populated on a // previous run because the user monitor crashed or was killed. Use // the existing key and let the values get overwritten. dwError = 0; } BAIL_ON_UMN_ERROR(dwError); dwError = RegCreateKeyExA( hReg, hKey, "Members", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hMembers, NULL); if (dwError == LWREG_ERROR_KEYNAME_EXIST) { // The key exists, but the values were not fully populated on a // previous run because the user monitor crashed or was killed. Use // the existing key and let the values get overwritten. dwError = 0; } BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupValues( hReg, hKey, pGroup); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, NULL, Now, pGroup); BAIL_ON_UMN_ERROR(dwError); } else if (strcmp(pGroup->groupInfo.pszUnixName, old.gr_name)) { // The group's name changed. This is too drastic of a change for a // change event. File a deletion and addition event. dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, &old, Now, NULL); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, NULL, Now, pGroup); BAIL_ON_UMN_ERROR(dwError); } else if (strcmp((pGroup->groupInfo.pszPasswd ? pGroup->groupInfo.pszPasswd : "x"), old.gr_passwd) || pGroup->groupInfo.gid != old.gr_gid) { UMN_LOG_INFO("Group '%s' (gid %d) changed", pGroup->groupInfo.pszUnixName, pGroup->groupInfo.gid); dwError = UmnSrvWriteADGroupValues( hReg, hKey, pGroup); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, &old, Now, pGroup); BAIL_ON_UMN_ERROR(dwError); if (pGroup->groupInfo.gid != old.gr_gid) { // Send out membership deletion events for all members. They // will get readded through normal processing with the new gid dwError = RegOpenKeyExA( hReg, hKey, "Members", 0, KEY_ALL_ACCESS, &hMembers); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvFindDeletedGroupMembers( pEventlog, hReg, "AD Groups", hMembers, Now, TRUE, old.gr_gid, old.gr_name); 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(pEncodedGroup); UmnSrvFreeGroupContents(&old); if (hKey) { RegCloseKey( hReg, hKey); } if (hMembers) { RegCloseKey( hReg, hMembers); } return dwError; error: goto cleanup; }