Author: nkinder
Update of /cvs/dirsec/ldapserver/ldap/synctools/passwordsync/passhook
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv2067/passwordsync/passhook
Modified Files:
Tag: Directory71RtmBranch
passhook.cpp
Log Message:
186657 - Implemented locking around passhook data file access
Index: passhook.cpp
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/synctools/passwordsync/passhook/passhook.cpp,v
retrieving revision 1.7.2.1
retrieving revision 1.7.2.2
diff -u -r1.7.2.1 -r1.7.2.2
--- passhook.cpp 22 Mar 2006 18:53:32 -0000 1.7.2.1
+++ passhook.cpp 30 Mar 2006 23:08:59 -0000 1.7.2.2
@@ -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", ®Key);
- 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);
- }
- 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);
-
- 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';
+ // 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 {
- if(outLog.is_open()) {
- timeStamp(&outLog);
- outLog << "failed to allocate memory for username and password"
<< endl;
- }
- free(newPassInfo.username);
- free(newPassInfo.password);
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;
- }
+ // 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';
- // 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;
- }
+ // Backoff
+ newPassInfo->backoffCount = 0;
+
+ // Load time
+ time(&(newPassInfo->atTime));
+ } else {
+ // Memory error. Free everything we allocated.
+ free(newPassInfo->username);
+ free(newPassInfo->password);
+ free(newPassInfo);
+ goto exit;
}
- // Add the new change to the list
- passInfoList.push_back(newPassInfo);
+ // Fire off a thread to do the real work
+ passhookThreadHandle = CreateThread(NULL, 0, SavePasshookChange, newPassInfo, 0, NULL);
- // 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;
- }
- }
+ // 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);
- // We need to call clearSet so memory gets free'd
- clearSet(&passInfoList);
+ // 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);
+
+ 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 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", ®Key);
+ 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;
}