diff options
Diffstat (limited to 'private/net/svcdlls/lls/server/llsutil.c')
-rw-r--r-- | private/net/svcdlls/lls/server/llsutil.c | 982 |
1 files changed, 982 insertions, 0 deletions
diff --git a/private/net/svcdlls/lls/server/llsutil.c b/private/net/svcdlls/lls/server/llsutil.c new file mode 100644 index 000000000..6b52e6791 --- /dev/null +++ b/private/net/svcdlls/lls/server/llsutil.c @@ -0,0 +1,982 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + LlsUtil.c + +Abstract: + + +Author: + + Arthur Hanson (arth) Dec 07, 1994 + +Environment: + +Revision History: + + Jeff Parham (jeffparh) 12-Jan-1996 + o Added WinNtBuildNumberGet() to ascertain the Windows NT build number + running on a given machine. + o Enhanced output of TimeToString(). + +--*/ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntlsa.h> + +#include <windows.h> +#include <stdlib.h> +#include <crypt.h> +#include <wchar.h> + +#include "debug.h" +#include "llssrv.h" + + +char HeaderString[] = "License Logging System Data File\x01A"; +#define HEADER_SIZE 34 + +typedef struct _LLS_FILE_HEADER { + char Header[HEADER_SIZE]; + DWORD Version; + DWORD DataSize; +} LLS_FILE_HEADER, *PLLS_FILE_HEADER; + + + +///////////////////////////////////////////////////////////////////////// +NTSTATUS +EBlock( + PVOID Data, + ULONG DataSize + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + DATA_KEY PublicKey; + CRYPT_BUFFER CryptBuffer; + + // + // Init our public key + // + PublicKey.Length = 4; + PublicKey.MaximumLength = 4; + PublicKey.Buffer = LocalAlloc(LPTR, 4); + + if (PublicKey.Buffer != NULL) { + ((char *) (PublicKey.Buffer))[0] = '7'; + ((char *) (PublicKey.Buffer))[1] = '7'; + ((char *) (PublicKey.Buffer))[2] = '7'; + ((char *) (PublicKey.Buffer))[3] = '7'; + + CryptBuffer.Length = DataSize; + CryptBuffer.MaximumLength = DataSize; + CryptBuffer.Buffer = (PVOID) Data; + Status = RtlEncryptData2(&CryptBuffer, &PublicKey); + + LocalFree(PublicKey.Buffer); + } else + Status = STATUS_NO_MEMORY; + + return Status; +} // EBlock + + +///////////////////////////////////////////////////////////////////////// +NTSTATUS +DeBlock( + PVOID Data, + ULONG DataSize + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + DATA_KEY PublicKey; + CRYPT_BUFFER CryptBuffer; + + // + // Init our public key + // + PublicKey.Length = 4; + PublicKey.MaximumLength = 4; + PublicKey.Buffer = LocalAlloc(LPTR, 4); + if (PublicKey.Buffer != NULL) { + ((char *) (PublicKey.Buffer))[0] = '7'; + ((char *) (PublicKey.Buffer))[1] = '7'; + ((char *) (PublicKey.Buffer))[2] = '7'; + ((char *) (PublicKey.Buffer))[3] = '7'; + + CryptBuffer.Length = DataSize; + CryptBuffer.MaximumLength = DataSize; + CryptBuffer.Buffer = (PVOID) Data; + Status = RtlDecryptData2(&CryptBuffer, &PublicKey); + + LocalFree(PublicKey.Buffer); + } else + Status = STATUS_NO_MEMORY; + + return Status; +} // DeBlock + + +///////////////////////////////////////////////////////////////////////// +BOOL +FileExists( + LPTSTR FileName + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + return (BOOL) RtlDoesFileExists_U(FileName); + +} // FileExists + + +///////////////////////////////////////////////////////////////////////// +VOID +lsplitpath( + const TCHAR *path, + TCHAR *drive, + TCHAR *dir, + TCHAR *fname, + TCHAR *ext + ) + +/*++ + +Routine Description: + Splits a path name into its individual components + + Took the _splitpath and _makepath routines and converted them to + be NT (long file name) and Unicode friendly. + +Arguments: + Entry: + path - pointer to path name to be parsed + drive - pointer to buffer for drive component, if any + dir - pointer to buffer for subdirectory component, if any + fname - pointer to buffer for file base name component, if any + ext - pointer to buffer for file name extension component, if any + + Exit: + drive - pointer to drive string. Includes ':' if a drive was given. + dir - pointer to subdirectory string. Includes leading and + trailing '/' or '\', if any. + fname - pointer to file base name + ext - pointer to file extension, if any. Includes leading '.'. + +Return Value: + + +--*/ + +{ + TCHAR *p; + TCHAR *last_slash = NULL, *dot = NULL; + unsigned len; + + // init these so we don't exit with bogus values + drive[0] = TEXT('\0'); + dir[0] = TEXT('\0'); + fname[0] = TEXT('\0'); + ext[0] = TEXT('\0'); + + if (path[0] == TEXT('\0')) + return; + + /*+---------------------------------------------------------------------+ + | Assume that the path argument has the following form, where any or | + | all of the components may be missing. | + | | + | <drive><dir><fname><ext> | + | | + | drive: | + | 0 to MAX_DRIVE-1 characters, the last of which, if any, is a | + | ':' or a '\' in the case of a UNC path. | + | dir: | + | 0 to _MAX_DIR-1 characters in the form of an absolute path | + | (leading '/' or '\') or relative path, the last of which, if | + | any, must be a '/' or '\'. E.g - | + | | + | absolute path: | + | \top\next\last\ ; or | + | /top/next/last/ | + | relative path: | + | top\next\last\ ; or | + | top/next/last/ | + | Mixed use of '/' and '\' within a path is also tolerated | + | fname: | + | 0 to _MAX_FNAME-1 characters not including the '.' character | + | ext: | + | 0 to _MAX_EXT-1 characters where, if any, the first must be a | + | '.' | + +---------------------------------------------------------------------+*/ + + // extract drive letter and :, if any + if ( path[0] && (path[1] == TEXT(':')) ) { + if (drive) { + drive[0] = path[0]; + drive[1] = path[1]; + drive[2] = TEXT('\0'); + } + path += 2; + } + + // if no drive then check for UNC pathname + if (drive[0] == TEXT('\0')) + if ((path[0] == TEXT('\\')) && (path[1] == TEXT('\\'))) { + // got a UNC path so put server-sharename into drive + drive[0] = path[0]; + drive[1] = path[1]; + path += 2; + + p = &drive[2]; + while ((*path != TEXT('\0')) && (*path != TEXT('\\'))) + *p++ = *path++; + + if (*path == TEXT('\0')) + return; + + // now sitting at the share - copy this as well (copy slash first) + *p++ = *path++; + while ((*path != TEXT('\0')) && (*path != TEXT('\\'))) + *p++ = *path++; + + // tack on terminating NULL + *p = TEXT('\0'); + } + + /*+---------------------------------------------------------------------+ + | extract path string, if any. Path now points to the first character| + | of the path, if any, or the filename or extension, if no path was | + | specified. Scan ahead for the last occurence, if any, of a '/' or | + | '\' path separator character. If none is found, there is no path. | + | We will also note the last '.' character found, if any, to aid in | + | handling the extension. | + +---------------------------------------------------------------------+*/ + + for (last_slash = NULL, p = (TCHAR *)path; *p; p++) { + if (*p == TEXT('/') || *p == TEXT('\\')) + // point to one beyond for later copy + last_slash = p + 1; + else if (*p == TEXT('.')) + dot = p; + } + + if (last_slash) { + + // found a path - copy up through last_slash or max. characters allowed, + // whichever is smaller + if (dir) { + len = __min((last_slash - path), (_MAX_DIR - 1)); + lstrcpyn(dir, path, len + 1); + dir[len] = TEXT('\0'); + } + path = last_slash; + } + + /*+---------------------------------------------------------------------+ + | extract file name and extension, if any. Path now points to the | + | first character of the file name, if any, or the extension if no | + | file name was given. Dot points to the '.' beginning the extension,| + | if any. | + +---------------------------------------------------------------------+*/ + + if (dot && (dot >= path)) { + // found the marker for an extension - copy the file name up to the + // '.'. + if (fname) { + len = __min((dot - path), (_MAX_FNAME - 1)); + lstrcpyn(fname, path, len + 1); + *(fname + len) = TEXT('\0'); + } + + // now we can get the extension - remember that p still points to the + // terminating nul character of path. + if (ext) { + len = __min((p - dot), (_MAX_EXT - 1)); + lstrcpyn(ext, dot, len + 1); + ext[len] = TEXT('\0'); + } + } + else { + // found no extension, give empty extension and copy rest of string + // into fname. + if (fname) { + len = __min((p - path), (_MAX_FNAME - 1)); + lstrcpyn(fname, path, len + 1); + fname[len] = TEXT('\0'); + } + if (ext) { + *ext = TEXT('\0'); + } + } + +} // lsplitpath + + +///////////////////////////////////////////////////////////////////////// +VOID +lmakepath( + TCHAR *path, + const TCHAR *drive, + const TCHAR *dir, + const TCHAR *fname, + const TCHAR *ext + ) + +/*++ + +Routine Description: + Create a path name from its individual components. + +Arguments: + Entry: + char *path - pointer to buffer for constructed path + char *drive - pointer to drive component, may or may not contain + trailing ':' + char *dir - pointer to subdirectory component, may or may not include + leading and/or trailing '/' or '\' characters + char *fname - pointer to file base name component + char *ext - pointer to extension component, may or may not contain + a leading '.'. + + Exit: + path - pointer to constructed path name + +Return Value: + + +--*/ + +{ + const TCHAR *p; + + /*+---------------------------------------------------------------------+ + | we assume that the arguments are in the following form (although we | + | do not diagnose invalid arguments or illegal filenames (such as | + | names longer than 8.3 or with illegal characters in them) | + | | + | drive: | + | A or A: | + | dir: | + | \top\next\last\ ; or | + | /top/next/last/ ; or | + | | + | either of the above forms with either/both the leading and | + | trailing / or \ removed. Mixed use of '/' and '\' is also | + | tolerated | + | fname: | + | any valid file name | + | ext: | + | any valid extension (none if empty or null ) | + +---------------------------------------------------------------------+*/ + + // copy drive + if (drive && *drive) + while (*drive) + *path++ = *drive++; + + // copy dir + if ((p = dir) && *p) { + do { + *path++ = *p++; + } + while (*p); + if ((*(p-1) != TEXT('/')) && (*(p-1) != TEXT('\\'))) { + *path++ = TEXT('\\'); + } + } + + // copy fname + if (p = fname) { + while (*p) { + *path++ = *p++; + } + } + + // copy ext, including 0-terminator - check to see if a '.' needs to be + // inserted. + if (p = ext) { + if (*p && *p != TEXT('.')) { + *path++ = TEXT('.'); + } + while (*path++ = *p++) + ; + } + else { + // better add the 0-terminator + *path = TEXT('\0'); + } + +} // lmakepath + + +///////////////////////////////////////////////////////////////////////// +VOID +FileBackupCreate( + LPTSTR Path + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + HANDLE hFile = NULL; + DWORD dwFileNumber = 0; + TCHAR Drive[_MAX_DRIVE + 1]; + TCHAR Dir[_MAX_DIR + 1]; + TCHAR FileName[_MAX_FNAME + 1]; + TCHAR Ext[_MAX_EXT + 1]; + TCHAR NewExt[_MAX_EXT + 1]; + TCHAR NewPath[MAX_PATH + 1]; + + // + // Make sure file exists + // + if (!FileExists(FileName)) + return; + + // + // Split name into constituent parts... + // + lsplitpath(Path, Drive, Dir, FileName, Ext); + + // Find next backup number... + // Files are backed up as .xxx where xxx is a number in the form .001, + // the first backup is stored as .001, second as .002, etc... + do { + // + // Create new file name with backup extension + // + dwFileNumber++; + wsprintf(NewExt, TEXT("%03u"), dwFileNumber); + lmakepath(NewPath, Drive, Dir, FileName, NewExt); + + } while ( FileExists(NewPath) ); + + MoveFile( Path, NewPath ); + +} // FileBackupCreate + + +///////////////////////////////////////////////////////////////////////// +HANDLE +LlsFileInit( + LPTSTR FileName, + DWORD Version, + DWORD DataSize + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + HANDLE hFile = NULL; + LLS_FILE_HEADER Header; + DWORD BytesWritten; + +#ifdef DEBUG + if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_DATABASE)) + dprintf(TEXT("LLS TRACE: LlsFileInit\n")); +#endif + + if (FileName == NULL) + return NULL; + + strcpy(Header.Header, HeaderString); + Header.Version = Version; + Header.DataSize = DataSize; + + SetFileAttributes(FileName, FILE_ATTRIBUTE_NORMAL); + hFile = CreateFile(FileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + if (!WriteFile(hFile, &Header, sizeof(LLS_FILE_HEADER), &BytesWritten, NULL)) { + CloseHandle(hFile); + hFile = NULL; + } + } + + return hFile; +} // LlsFileInit + + +///////////////////////////////////////////////////////////////////////// +HANDLE +LlsFileCheck( + LPTSTR FileName, + LPDWORD Version, + LPDWORD DataSize + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + BOOL FileOK = FALSE; + HANDLE hFile = NULL; + LLS_FILE_HEADER Header; + DWORD FileSize; + DWORD BytesRead; + +#ifdef DEBUG + if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_DATABASE)) + dprintf(TEXT("LLS TRACE: LlsFileCheck\n")); +#endif + + if (FileName == NULL) + return NULL; + + // + // We are assuming the file exists + // + SetFileAttributes(FileName, FILE_ATTRIBUTE_NORMAL); + hFile = CreateFile(FileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + FileSize = GetFileSize(hFile, NULL); + + // + // Make sure there is enough data there to read + // + if (FileSize > (sizeof(LLS_FILE_HEADER) + 1)) { + if (ReadFile(hFile, &Header, sizeof(LLS_FILE_HEADER), &BytesRead, NULL)) { + if ( !_strcmpi(Header.Header, HeaderString) ) { + // + // Data checks out - so return datalength + // + *Version = Header.Version; + *DataSize = Header.DataSize; + FileOK = TRUE; + } + } + } + + // + // If we opened the file and something was wrong - close it. + // + if (!FileOK) { + CloseHandle(hFile); + hFile = NULL; + } + } + + return hFile; + +} // LlsFileCheck + + +///////////////////////////////////////////////////////////////////////// +DWORD +DateSystemGet( + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + Seconds since midnight. + +--*/ + +{ + DWORD Seconds; + LARGE_INTEGER SysTime; + + NtQuerySystemTime(&SysTime); + RtlTimeToSecondsSince1980(&SysTime, &Seconds); + return Seconds; + +} // DateSystemGet + + +///////////////////////////////////////////////////////////////////////// +DWORD +DateLocalGet( + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + Seconds since midnight. + +--*/ + +{ + DWORD Seconds; + LARGE_INTEGER SysTime, LocalTime; + + NtQuerySystemTime(&SysTime); + RtlSystemTimeToLocalTime(&SysTime, &LocalTime); + RtlTimeToSecondsSince1980(&LocalTime, &Seconds); + return Seconds; + +} // DateLocalGet + + +///////////////////////////////////////////////////////////////////////// +DWORD +InAWorkgroup( + VOID + ) +/*++ + +Routine Description: + + This function determines whether we are a member of a domain, or of + a workgroup. First it checks to make sure we're running on a Windows NT + system (otherwise we're obviously in a domain) and if so, queries LSA + to get the Primary domain SID, if this is NULL, we're in a workgroup. + + If we fail for some random unexpected reason, we'll pretend we're in a + workgroup (it's more restrictive). + +Arguments: + None + +Return Value: + + TRUE - We're in a workgroup + FALSE - We're in a domain + +--*/ +{ + NT_PRODUCT_TYPE ProductType; + OBJECT_ATTRIBUTES ObjectAttributes; + LSA_HANDLE Handle; + NTSTATUS Status; + PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo = NULL; + DWORD Result = FALSE; + + + Status = RtlGetNtProductType(&ProductType); + + if (!NT_SUCCESS(Status)) { +#if DBG + dprintf(TEXT("ERROR LLS Could not get Product type\n")); +#endif + return TRUE; + } + + if (ProductType == NtProductLanManNt) { + return(FALSE); + } + + InitializeObjectAttributes(&ObjectAttributes, NULL, 0, 0, NULL); + + Status = LsaOpenPolicy(NULL, + &ObjectAttributes, + POLICY_VIEW_LOCAL_INFORMATION, + &Handle); + + if (!NT_SUCCESS(Status)) { +#if DBG + dprintf(TEXT("ERROR LLS: Could not open LSA Policy Database\n")); +#endif + return TRUE; + } + + Status = LsaQueryInformationPolicy(Handle, PolicyPrimaryDomainInformation, + (PVOID *) &PolicyPrimaryDomainInfo); + + if (NT_SUCCESS(Status)) { + + if (PolicyPrimaryDomainInfo->Sid == NULL) { + Result = TRUE; + } + else { + Result = FALSE; + } + } + + if (PolicyPrimaryDomainInfo) { + LsaFreeMemory((PVOID)PolicyPrimaryDomainInfo); + } + + LsaClose(Handle); + + return(Result); +} // InAWorkgroup + + +///////////////////////////////////////////////////////////////////////// +VOID +LogEvent( + DWORD MessageId, + DWORD NumberOfSubStrings, + LPWSTR *SubStrings, + DWORD ErrorCode + ) +{ + + HANDLE LogHandle; + WORD wEventType; + + LogHandle = RegisterEventSourceW ( + NULL, + TEXT("LicenseService") + ); + + if (LogHandle == NULL) { +#if DBG + dprintf(TEXT("LLS RegisterEventSourceW failed %lu\n"), GetLastError()); +#endif + return; + } + + switch ( MessageId >> 30 ) + { + case STATUS_SEVERITY_INFORMATIONAL: + case STATUS_SEVERITY_SUCCESS: + wEventType = EVENTLOG_INFORMATION_TYPE; + break; + case STATUS_SEVERITY_WARNING: + wEventType = EVENTLOG_WARNING_TYPE; + break; + case STATUS_SEVERITY_ERROR: + default: + wEventType = EVENTLOG_ERROR_TYPE; + break; + } + + if (ErrorCode == ERROR_SUCCESS) { + + // + // No error codes were specified + // + (void) ReportEventW( + LogHandle, + wEventType, + 0, // event category + MessageId, + NULL, + (WORD)NumberOfSubStrings, + 0, + SubStrings, + (PVOID) NULL + ); + + } + else { + + // + // Log the error code specified + // + (void) ReportEventW( + LogHandle, + wEventType, + 0, // event category + MessageId, + NULL, + (WORD)NumberOfSubStrings, + sizeof(DWORD), + SubStrings, + (PVOID) &ErrorCode + ); + } + + DeregisterEventSource(LogHandle); +} // LogEvent + + +///////////////////////////////////////////////////////////////////////// +DWORD WinNtBuildNumberGet( LPTSTR pszServerName, LPDWORD pdwBuildNumber ) + +/*++ + +Routine Description: + + Retrieve the build number of Windows NT running on a given machine. + +Arguments: + + pszServerName (LPTSTR) + Name of the server to check. + pdwBuildNumber (LPDWORD) + On return, holds the build number of the server (e.g., 1057 for the + release version of Windows NT 3.51). + +Return Value: + + ERROR_SUCCESS or Win error code. + +--*/ + +{ + LONG lError; + HKEY hKeyLocalMachine; + + lError = RegConnectRegistry( pszServerName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine ); + + if ( ERROR_SUCCESS != lError ) + { +#if DBG + dprintf( TEXT("WinNtBuildNumberGet(): Could not connect to remote registry, error %ld.\n"), lError ); +#endif + } + else + { + HKEY hKeyCurrentVersion; + + lError = RegOpenKeyEx( hKeyLocalMachine, + TEXT( "Software\\Microsoft\\Windows NT\\CurrentVersion" ), + 0, + KEY_READ, + &hKeyCurrentVersion ); + + if ( ERROR_SUCCESS != lError ) + { +#if DBG + dprintf( TEXT("WinNtBuildNumberGet(): Could not open key, error %ld.\n"), lError ); +#endif + } + else + { + DWORD dwType; + TCHAR szWinNtBuildNumber[ 16 ]; + DWORD cbWinNtBuildNumber = sizeof( szWinNtBuildNumber ); + + lError = RegQueryValueEx( hKeyCurrentVersion, + TEXT( "CurrentBuildNumber" ), + NULL, + &dwType, + (LPBYTE) &szWinNtBuildNumber, + &cbWinNtBuildNumber ); + + if ( ERROR_SUCCESS != lError ) + { +#if DBG + dprintf( TEXT("WinNtBuildNumberGet(): Could not query value, error %ld.\n"), lError ); +#endif + } + else + { + *pdwBuildNumber = (DWORD) _wtol( szWinNtBuildNumber ); + } + + RegCloseKey( hKeyCurrentVersion ); + } + + RegCloseKey( hKeyLocalMachine ); + } + + return (DWORD) lError; +} + + +#if DBG + +///////////////////////////////////////////////////////////////////////// +LPTSTR +TimeToString( + ULONG Seconds + ) +{ + TIME_FIELDS tf; + LARGE_INTEGER Time, LTime; + static TCHAR TimeString[100]; + + if ( 0 == Seconds ) + { + lstrcpy(TimeString, TEXT("None")); + } + else + { + RtlSecondsSince1980ToTime(Seconds, &Time); + RtlSystemTimeToLocalTime(&Time, <ime); + RtlTimeToTimeFields(<ime, &tf); + + wsprintf(TimeString, TEXT("%02hd/%02hd/%04hd @ %02hd:%02hd:%02hd"), tf.Month, tf.Day, tf.Year, tf.Hour, tf.Minute, tf.Second); + } + + return TimeString; + +} // TimeToString + +#endif + |