Index: base/system/services/rpcserver.c =================================================================== --- base/system/services/rpcserver.c (révision 56767) +++ base/system/services/rpcserver.c (copie de travail) @@ -15,8 +15,26 @@ #define NDEBUG #include +#include + /* GLOBALS *****************************************************************/ +/* + * Structure describing a user database lock. + */ +#define LOCK_TAG 0x4C697041 /* 'ApiL' */ + +typedef struct _SC_LOCK_STRUCT +{ + DWORD Tag; /* Must be LOCK_TAG */ + LPWSTR DatabaseName; + DWORD TimeWhenLocked; /* Number of seconds since 1970 */ + PSID LockOwnerSid; /* It is NULL if SC Manager grabbed the lock */ +} SC_LOCK_STRUCT, *PSC_LOCK_STRUCT; + +PSC_LOCK_STRUCT SCActiveDatabaseLock = NULL; + + #define MANAGER_TAG 0x72674D68 /* 'hMgr' */ #define SERVICE_TAG 0x63765368 /* 'hSvc' */ @@ -1298,6 +1316,58 @@ } +static DWORD +ScmLockDatabase(IN BOOL IsServiceController, // TRUE if locked by the Service Control Manager, FALSE otherwise. + IN LPWSTR DatabaseName, + OUT LPSC_RPC_LOCK lpLock) +{ + DWORD bufSize = 0; + + *lpLock = NULL; + + if (SCActiveDatabaseLock != NULL) + { + return ERROR_SERVICE_DATABASE_LOCKED; + } + else + { + /* + * Allocate a new lock for the database. + */ + bufSize = sizeof(SC_LOCK_STRUCT) + (DatabaseName ? (wcslen(DatabaseName) + 1) * sizeof(WCHAR) : 0); + + if (!IsServiceController) + { + /* bufSize += RtlLengthSid(UserSid <-- to be retrieved); */ + } + + SCActiveDatabaseLock = (PSC_LOCK_STRUCT)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + bufSize); + if (SCActiveDatabaseLock == NULL) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + SCActiveDatabaseLock->Tag = LOCK_TAG; + + if (DatabaseName) + { + SCActiveDatabaseLock->DatabaseName = (LPWSTR)(SCActiveDatabaseLock + 1); + wcscpy(SCActiveDatabaseLock->DatabaseName, DatabaseName); + } + + SCActiveDatabaseLock->TimeWhenLocked = (DWORD)time(NULL); + /* FIXME: Retrieve the owner SID. Use IsServiceController. */ + SCActiveDatabaseLock->LockOwnerSid = (PSID)NULL; + + *lpLock = SCActiveDatabaseLock; + + return ERROR_SUCCESS; + } +} + + /* Function 3 */ DWORD RLockServiceDatabase( SC_RPC_HANDLE hSCManager, @@ -1307,7 +1377,8 @@ DPRINT("RLockServiceDatabase() called\n"); - *lpLock = 0; + // assert(lpLock); + *lpLock = NULL; hMgr = ScmGetServiceManagerFromHandle(hSCManager); if (hMgr == NULL) @@ -1320,12 +1391,9 @@ SC_MANAGER_LOCK)) return ERROR_ACCESS_DENIED; -// return ScmLockDatabase(0, hMgr->0xC, hLock); + DPRINT("RLockServiceDatabase() done\n"); - /* FIXME: Lock the database */ - *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */ - - return ERROR_SUCCESS; + return ScmLockDatabase(FALSE, hMgr->DatabaseName, lpLock); } @@ -1706,7 +1774,33 @@ DWORD RUnlockServiceDatabase( LPSC_RPC_LOCK Lock) { - UNIMPLEMENTED; + PSC_LOCK_STRUCT apiLock; + + DPRINT("RUnlockServiceDatabase() called\n"); + + if (Lock == NULL) + return ERROR_INVALID_SERVICE_LOCK; + + apiLock = *(PSC_LOCK_STRUCT*)Lock; + + if (apiLock->Tag != LOCK_TAG) + return ERROR_INVALID_SERVICE_LOCK; + + /* Release the lock handle */ + if ( (apiLock == SCActiveDatabaseLock) && + (SCActiveDatabaseLock != NULL) ) + { + HeapFree(GetProcessHeap(), 0, SCActiveDatabaseLock); + SCActiveDatabaseLock = NULL; + *Lock = NULL; + } + else + { + return ERROR_INVALID_SERVICE_LOCK; + } + + DPRINT("RUnlockServiceDatabase() done\n"); + return ERROR_SUCCESS; } @@ -2861,8 +2955,53 @@ DWORD cbBufSize, LPBOUNDED_DWORD_4K pcbBytesNeeded) { - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; + PMANAGER_HANDLE hMgr; + DWORD dwRequiredSize; + + if (!lpLockStatus || !pcbBytesNeeded) + return ERROR_INVALID_PARAMETER; + + hMgr = ScmGetServiceManagerFromHandle(hSCManager); + if (hMgr == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, + SC_MANAGER_QUERY_LOCK_STATUS)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* HACK: we need to compute instead the real length of the owner name */ + dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR); + *pcbBytesNeeded = dwRequiredSize; + + if (cbBufSize < dwRequiredSize) + return ERROR_INSUFFICIENT_BUFFER; + + if (SCActiveDatabaseLock) + { + lpLockStatus->fIsLocked = TRUE; + + /* FIXME: Retrieve the owner name. */ + lpLockStatus->lpLockOwner = NULL; + + lpLockStatus->dwLockDuration = (DWORD)time(NULL) - SCActiveDatabaseLock->TimeWhenLocked; + } + else + { + lpLockStatus->fIsLocked = FALSE; + + wcscpy((LPWSTR)(lpLockStatus + 1), L""); + lpLockStatus->lpLockOwner = (LPWSTR)(ULONG_PTR)sizeof(QUERY_SERVICE_LOCK_STATUSW); + + lpLockStatus->dwLockDuration = 0; + } + + return ERROR_SUCCESS; } @@ -4094,8 +4233,53 @@ DWORD cbBufSize, LPBOUNDED_DWORD_4K pcbBytesNeeded) { - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; + PMANAGER_HANDLE hMgr; + DWORD dwRequiredSize; + + if (!lpLockStatus || !pcbBytesNeeded) + return ERROR_INVALID_PARAMETER; + + hMgr = ScmGetServiceManagerFromHandle(hSCManager); + if (hMgr == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, + SC_MANAGER_QUERY_LOCK_STATUS)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* HACK: we need to compute instead the real length of the owner name */ + dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR); + *pcbBytesNeeded = dwRequiredSize; + + if (cbBufSize < dwRequiredSize) + return ERROR_INSUFFICIENT_BUFFER; + + if (SCActiveDatabaseLock) + { + lpLockStatus->fIsLocked = TRUE; + + /* FIXME: Retrieve the owner name. */ + lpLockStatus->lpLockOwner = NULL; + + lpLockStatus->dwLockDuration = (DWORD)time(NULL) - SCActiveDatabaseLock->TimeWhenLocked; + } + else + { + lpLockStatus->fIsLocked = FALSE; + + strcpy((LPSTR)(lpLockStatus + 1), ""); + lpLockStatus->lpLockOwner = (LPSTR)(ULONG_PTR)sizeof(QUERY_SERVICE_LOCK_STATUSA); + + lpLockStatus->dwLockDuration = 0; + } + + return ERROR_SUCCESS; }