summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Kinder <nkinder@redhat.com>2006-03-30 23:13:44 +0000
committerNathan Kinder <nkinder@redhat.com>2006-03-30 23:13:44 +0000
commitc242fa8095146bfae6fde258ab020360a9123bdb (patch)
tree3e420a808d01f543a66c9f554b2b6300681b0894
parent3f7f8b81faf1049106a442da088617c53b1e8e22 (diff)
186657 - Implemented locking around passhook data file access
-rw-r--r--ldap/synctools/passwordsync/passhand.cpp20
-rw-r--r--ldap/synctools/passwordsync/passhand.h2
-rw-r--r--ldap/synctools/passwordsync/passhook/passhook.cpp276
-rw-r--r--ldap/synctools/passwordsync/passsync/syncserv.cpp43
-rw-r--r--ldap/synctools/passwordsync/passsync/syncserv.h4
5 files changed, 231 insertions, 114 deletions
diff --git a/ldap/synctools/passwordsync/passhand.cpp b/ldap/synctools/passwordsync/passhand.cpp
index ddad1977..4cefd58c 100644
--- a/ldap/synctools/passwordsync/passhand.cpp
+++ b/ldap/synctools/passwordsync/passhand.cpp
@@ -112,6 +112,8 @@ int saveSet(PASS_INFO_LIST* passInfoList, char* filename)
outFile.close();
exit:
+ // We need to unfreeze plainTextStream so memory gets freed by the destructor
+ plainTextStream.rdbuf()->freeze(false);
free(cipherTextBuf);
return result;
}
@@ -119,18 +121,18 @@ exit:
int loadSet(PASS_INFO_LIST* passInfoList, char* filename)
{
int result = 0;
- int i;
+ int i = 0;
fstream inFile;
PASS_INFO newPair;
strstream* plainTextStream;
char* cipherTextBuf = NULL;
char* plainTextBuf = NULL;
- int usernameLen;
- int passwordLen;
- int plainTextLen;
- int cipherTextLen;
+ int usernameLen = 0;
+ int passwordLen = 0;
+ int plainTextLen = 0;
+ int cipherTextLen = 0;
int resultTextLen = 0;
- int pairCount;
+ int pairCount = 0;
// Read in cipher text from file
inFile.open(filename, ios::in | ios::binary);
@@ -164,6 +166,12 @@ int loadSet(PASS_INFO_LIST* passInfoList, char* filename)
goto exit;
}
+ // Check to see if plainTextbuf contains anything
+ if (resultTextLen <= 0) {
+ result = -1;
+ goto exit;
+ }
+
plainTextStream = new strstream(plainTextBuf, resultTextLen);
plainTextStream->read((char*)&pairCount, sizeof(pairCount));
diff --git a/ldap/synctools/passwordsync/passhand.h b/ldap/synctools/passwordsync/passhand.h
index 344e009a..27674789 100644
--- a/ldap/synctools/passwordsync/passhand.h
+++ b/ldap/synctools/passwordsync/passhand.h
@@ -50,7 +50,9 @@
#include "prerror.h"
#define PASSHAND_EVENT_NAME "passhand_event"
+#define PASSHOOK_MUTEX_NAME "passhook_mutex"
+#define PASSHOOK_TIMEOUT 30000
#define PASSHAND_BUF_SIZE 256
using namespace std;
diff --git a/ldap/synctools/passwordsync/passhook/passhook.cpp b/ldap/synctools/passwordsync/passhook/passhook.cpp
index eba277a2..e9ec0891 100644
--- a/ldap/synctools/passwordsync/passhook/passhook.cpp
+++ b/ldap/synctools/passwordsync/passhook/passhook.cpp
@@ -48,121 +48,74 @@
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
+DWORD WINAPI SavePasshookChange( LPVOID passinfo );
+static HANDLE passhookMutexHandle;
+static unsigned long logLevel;
+
NTSTATUS NTAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING Password)
{
- HANDLE passhookEventHandle = OpenEvent(EVENT_MODIFY_STATE, FALSE, PASSHAND_EVENT_NAME);
- PASS_INFO newPassInfo;
- PASS_INFO_LIST passInfoList;
- HKEY regKey;
- DWORD type;
- unsigned long buffSize;
- char regBuff[PASSHAND_BUF_SIZE];
- unsigned long logLevel;
+ PASS_INFO *newPassInfo = NULL;
+ HANDLE passhookThreadHandle;
fstream outLog;
+ DWORD waitRes;
- RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\PasswordSync", &regKey);
- buffSize = PASSHAND_BUF_SIZE;
- if(RegQueryValueEx(regKey, "Log Level", NULL, &type, (unsigned char*)regBuff, &buffSize) == ERROR_SUCCESS)
- {
- logLevel = (unsigned long)atoi(regBuff);
- }
- else
- {
- logLevel = 0;
- }
- if(logLevel > 0)
- {
- outLog.open("passhook.log", ios::out | ios::app);
+ // This memory will be freed in SavePasshookChange
+ if ( newPassInfo = (PASS_INFO *) malloc(sizeof(PASS_INFO)) ) {
+ // These get freed in SavePasshookChange by calling clearSet
+ newPassInfo->username = (char*)malloc((UserName->Length / 2) + 1);
+ newPassInfo->password = (char*)malloc((Password->Length / 2) + 1);
+ } else {
+ goto exit;
}
- RegCloseKey(regKey);
- // This memory will be free'd by calling clearSet below
- newPassInfo.username = (char*)malloc((UserName->Length / 2) + 1);
- newPassInfo.password = (char*)malloc((Password->Length / 2) + 1);
+ // Fill in the password change struct
+ if (newPassInfo->username && newPassInfo->password) {
+ _snprintf(newPassInfo->username, (UserName->Length / 2), "%S", UserName->Buffer);
+ _snprintf(newPassInfo->password, (Password->Length / 2), "%S", Password->Buffer);
+ newPassInfo->username[UserName->Length / 2] = '\0';
+ newPassInfo->password[Password->Length / 2] = '\0';
+
+ // Backoff
+ newPassInfo->backoffCount = 0;
- if (newPassInfo.username && newPassInfo.password) {
- _snprintf(newPassInfo.username, (UserName->Length / 2), "%S", UserName->Buffer);
- _snprintf(newPassInfo.password, (Password->Length / 2), "%S", Password->Buffer);
- newPassInfo.username[UserName->Length / 2] = '\0';
- newPassInfo.password[Password->Length / 2] = '\0';
+ // Load time
+ time(&(newPassInfo->atTime));
} else {
- if(outLog.is_open()) {
- timeStamp(&outLog);
- outLog << "failed to allocate memory for username and password" << endl;
- }
- free(newPassInfo.username);
- free(newPassInfo.password);
+ // Memory error. Free everything we allocated.
+ free(newPassInfo->username);
+ free(newPassInfo->password);
+ free(newPassInfo);
goto exit;
}
- if(outLog.is_open())
- {
- timeStamp(&outLog);
- outLog << "user " << newPassInfo.username << " password changed" << endl;
- //outLog << "user " << newPassInfo.username << " password changed to " << newPassInfo.password << endl;
- }
+ // Fire off a thread to do the real work
+ passhookThreadHandle = CreateThread(NULL, 0, SavePasshookChange, newPassInfo, 0, NULL);
- // loadSet allocates memory for the usernames and password. We need to be
- // sure to free it by calling clearSet.
- if(loadSet(&passInfoList, "passhook.dat") == 0)
- {
- if(outLog.is_open())
- {
- timeStamp(&outLog);
- outLog << passInfoList.size() << " entries loaded from file" << endl;
- }
- }
- else
- {
- if(outLog.is_open())
- {
- timeStamp(&outLog);
- outLog << "failed to load entries from file" << endl;
- }
- }
+ // We need to close the handle to the thread we created. Doing
+ // this will not terminate the thread.
+ if (passhookThreadHandle != NULL) {
+ CloseHandle(passhookThreadHandle);
+ } else {
+ // Acquire the mutex so we can log an error
+ waitRes = WaitForSingleObject(passhookMutexHandle, PASSHOOK_TIMEOUT);
- // Add the new change to the list
- passInfoList.push_back(newPassInfo);
-
- // Save the list to disk
- if(saveSet(&passInfoList, "passhook.dat") == 0)
- {
- if(outLog.is_open())
- {
- timeStamp(&outLog);
- outLog << passInfoList.size() << " entries saved to file" << endl;
- }
- }
- else
- {
- if(outLog.is_open())
- {
- timeStamp(&outLog);
- outLog << "failed to save entries to file" << endl;
- }
- }
+ // If we got the mutex, log the error, otherwise it's not safe to log
+ if (waitRes == WAIT_OBJECT_0) {
+ outLog.open("passhook.log", ios::out | ios::app);
- // We need to call clearSet so memory gets free'd
- clearSet(&passInfoList);
+ if(outLog.is_open()) {
+ timeStamp(&outLog);
+ outLog << "Failed to start thread. Aborting change for " << newPassInfo->username << endl;
+ }
-exit:
- if(passhookEventHandle == NULL)
- {
- if(outLog.is_open())
- {
- timeStamp(&outLog);
- outLog << "can not get password sync service event handle, service not running" << endl;
- }
+ outLog.close();
- }
- else
- {
- SetEvent(passhookEventHandle);
- CloseHandle(passhookEventHandle);
+ // Release mutex
+ ReleaseMutex(passhookMutexHandle);
+ }
}
- outLog.close();
-
+exit:
return STATUS_SUCCESS;
}
@@ -173,5 +126,132 @@ BOOL NTAPI PasswordFilter(PUNICODE_STRING UserName, PUNICODE_STRING FullName, PU
BOOL NTAPI InitializeChangeNotify()
{
- return TRUE;
+ HKEY regKey;
+ DWORD type;
+ unsigned long buffSize;
+ char regBuff[PASSHAND_BUF_SIZE];
+ fstream outLog;
+
+ // check if logging is enabled
+ RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\PasswordSync", &regKey);
+ buffSize = PASSHAND_BUF_SIZE;
+ if(RegQueryValueEx(regKey, "Log Level", NULL, &type, (unsigned char*)regBuff, &buffSize) == ERROR_SUCCESS)
+ {
+ logLevel = (unsigned long)atoi(regBuff);
+ }
+ else
+ {
+ logLevel = 0;
+ }
+ RegCloseKey(regKey);
+
+ // Create mutex for passhook data file and log file access
+ passhookMutexHandle = CreateMutex(NULL, FALSE, PASSHOOK_MUTEX_NAME);
+
+ if (passhookMutexHandle == NULL) {
+ // Log an error.
+ outLog.open("passhook.log", ios::out | ios::app);
+ timeStamp(&outLog);
+ outLog << "Failed to create passhook mutex. Passhook DLL will not be loaded." << endl;
+ outLog.close();
+
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+// This function will save the password change to the passhook data file. It
+// will be run as a separate thread.
+DWORD WINAPI SavePasshookChange( LPVOID passinfo )
+{
+ PASS_INFO *newPassInfo = NULL;
+ PASS_INFO_LIST passInfoList;
+ HANDLE passhookEventHandle = OpenEvent(EVENT_MODIFY_STATE, FALSE, PASSHAND_EVENT_NAME);
+ fstream outLog;
+
+ if ((newPassInfo = (PASS_INFO *)passinfo) == NULL) {
+ goto exit;
+ }
+
+ // Acquire the mutex for passhook.dat. This mutex also guarantees
+ // that we can write to outLog safely.
+ WaitForSingleObject(passhookMutexHandle, INFINITE);
+
+ // Open the log file if logging is enabled
+ if(logLevel > 0)
+ {
+ outLog.open("passhook.log", ios::out | ios::app);
+ }
+
+ if(outLog.is_open())
+ {
+ timeStamp(&outLog);
+ outLog << "user " << newPassInfo->username << " password changed" << endl;
+ //outLog << "user " << newPassInfo->username << " password changed to " << newPassInfo->passname << endl;
+ }
+
+ // loadSet allocates memory for the usernames and password. We need to be
+ // sure to free it by calling clearSet.
+ if(loadSet(&passInfoList, "passhook.dat") == 0)
+ {
+ if(outLog.is_open())
+ {
+ timeStamp(&outLog);
+ outLog << passInfoList.size() << " entries loaded from file" << endl;
+ }
+ }
+ else
+ {
+ if(outLog.is_open())
+ {
+ timeStamp(&outLog);
+ outLog << "failed to load entries from file" << endl;
+ }
+ }
+
+ // Add the new change to the list
+ passInfoList.push_back(*newPassInfo);
+
+ // Save the list to disk
+ if(saveSet(&passInfoList, "passhook.dat") == 0)
+ {
+ if(outLog.is_open())
+ {
+ timeStamp(&outLog);
+ outLog << passInfoList.size() << " entries saved to file" << endl;
+ }
+ }
+ else
+ {
+ // We always want to log this error condition
+ if(!outLog.is_open())
+ {
+ // We need to open the log since debug logging is turned off
+ outLog.open("passhook.log", ios::out | ios::app);
+ }
+
+ timeStamp(&outLog);
+ outLog << "failed to save entries to file" << endl;
+ }
+
+ // Close the log file before we release the mutex.
+ outLog.close();
+
+ // Release the mutex for passhook.dat
+ ReleaseMutex(passhookMutexHandle);
+
+ // We need to call clearSet so memory gets free'd
+ clearSet(&passInfoList);
+
+exit:
+ // Free the passed in struct from the heap
+ free(newPassInfo);
+
+ if (passhookEventHandle != NULL) {
+ SetEvent(passhookEventHandle);
+ CloseHandle(passhookEventHandle);
+ }
+
+ return 0;
}
diff --git a/ldap/synctools/passwordsync/passsync/syncserv.cpp b/ldap/synctools/passwordsync/passsync/syncserv.cpp
index 63bb451e..6e314f8e 100644
--- a/ldap/synctools/passwordsync/passsync/syncserv.cpp
+++ b/ldap/synctools/passwordsync/passsync/syncserv.cpp
@@ -76,6 +76,7 @@ PassSyncService::PassSyncService(const TCHAR *serviceName) : CNTService(serviceN
unsigned long size;
passhookEventHandle = CreateEvent(NULL, FALSE, FALSE, PASSHAND_EVENT_NAME);
+ passhookMutexHandle = CreateMutex(NULL, FALSE, PASSHOOK_MUTEX_NAME);
mainLdapConnection = NULL;
results = NULL;
currentResult = NULL;
@@ -211,10 +212,14 @@ void PassSyncService::Run()
timeStamp(&outLog);
outLog << "Backing off for " << BackoffTime(GetMinBackoff()) << "ms" << endl;
}
- WaitForSingleObject(passhookEventHandle, BackoffTime(GetMinBackoff()));
+ waitRes = WaitForSingleObject(passhookEventHandle, BackoffTime(GetMinBackoff()));
if(logLevel > 0) {
timeStamp(&outLog);
- outLog << "Backoff time expired. Attempting sync" << endl;
+ if (waitRes == WAIT_TIMEOUT) {
+ outLog << "Backoff time expired. Attempting sync" << endl;
+ } else {
+ outLog << "Received passhook event. Attempting sync" << endl;
+ }
}
}
@@ -226,24 +231,38 @@ void PassSyncService::Run()
if(passInfoList.size() > 0)
{
- if(saveSet(&passInfoList, dataFilename) == 0)
+ // Get mutex for passhook.dat
+ WaitForSingleObject(passhookMutexHandle, INFINITE);
+
+ // Need to loadSet here so we don't overwrite entries that passhook recently added
+ if(loadSet(&passInfoList, dataFilename) == 0)
{
- if(logLevel > 0)
+ if(saveSet(&passInfoList, dataFilename) == 0)
+ {
+ if(logLevel > 0)
+ {
+ timeStamp(&outLog);
+ outLog << passInfoList.size() << " entries saved to data file" << endl;
+ }
+ }
+ else
{
timeStamp(&outLog);
- outLog << passInfoList.size() << " entries saved to data file" << endl;
+ outLog << "Failed to save entries to data file" << endl;
}
- }
- else
- {
+ } else {
timeStamp(&outLog);
- outLog << "Failed to save entries to data file" << endl;
+ outLog << "Failed to load entries from file" << endl;
}
+
+ // Release mutex for passhook.dat
+ ReleaseMutex(passhookMutexHandle);
}
exit:
clearSet(&passInfoList);
CloseHandle(passhookEventHandle);
+ CloseHandle(passhookMutexHandle);
}
// ****************************************************************
@@ -258,6 +277,9 @@ int PassSyncService::SyncPasswords()
char* dn = NULL;
int tempSize = passInfoList.size();
+ // Get mutex for passhook.dat
+ WaitForSingleObject(passhookMutexHandle, INFINITE);
+
if(loadSet(&passInfoList, dataFilename) == 0)
{
if((passInfoList.size() - tempSize) > 0)
@@ -289,6 +311,9 @@ int PassSyncService::SyncPasswords()
outLog << "Failed to load entries from file" << endl;
}
+ // Release mutex for passhook.dat
+ ReleaseMutex(passhookMutexHandle);
+
if(passInfoList.size() > 0)
{
if(logLevel > 0)
diff --git a/ldap/synctools/passwordsync/passsync/syncserv.h b/ldap/synctools/passwordsync/passsync/syncserv.h
index c072114d..4c1a9a13 100644
--- a/ldap/synctools/passwordsync/passsync/syncserv.h
+++ b/ldap/synctools/passwordsync/passsync/syncserv.h
@@ -82,6 +82,7 @@ private:
PASS_INFO_LIST passInfoList;
HANDLE passhookEventHandle;
+ HANDLE passhookMutexHandle;
// LDAP variables
LDAP* mainLdapConnection;
@@ -104,7 +105,8 @@ private:
unsigned long maxBackoffTime;
int logLevel;
bool isRunning;
+ DWORD waitRes;
fstream outLog;
};
-#endif \ No newline at end of file
+#endif