/*++ Copyright (c) 1991 Microsoft Corporation Module Name: testserv.c Abstract: This is a test program for exercising the service controller. This program acts like a service and exercises the Service Controller API that can be called from a service: NetServiceStartCtrlDispatcher NetServiceRegisterCtrlHandler NetServiceStatus Author: Dan Lafferty (danl) 12 Apr-1991 Environment: User Mode -Win32 Notes: optional-notes Revision History: --*/ // // Includes // #define UNICODE 1 #include // DbgPrint prototype #include // DbgPrint prototype #include #include // needed for winbase.h #include #include #include // MessageBox #include // Unicode string macros #include // NET_API_STATUS for srvann.h //#include // I_ScSetServiceBits #include // SV_TYPE_WORKSTATION, SetServiceBits // // Defines // #define PRIVILEGE_BUF_SIZE 512 #define INFINITE_WAIT_TIME 0xffffffff #define NULL_STRING TEXT(""); // // Macros // #define SET_LKG_ENV_VAR(pString) \ { \ NTSTATUS NtStatus; \ UNICODE_STRING Name,Value; \ \ RtlInitUnicodeString(&Name, L"LastKnownGood"); \ RtlInitUnicodeString(&Value,pString); \ \ NtStatus = NtSetSystemEnvironmentValue(&Name,&Value); \ if (!NT_SUCCESS(NtStatus)) { \ DbgPrint("Failed to set LKG environment variable 0x%lx\n",NtStatus); \ } \ status = RtlNtStatusToDosError(NtStatus); \ } // // Globals // SERVICE_STATUS MsgrStatus; SERVICE_STATUS SmfStaStatus; SERVICE_STATUS LogonStatus; HANDLE MessingerDoneEvent; HANDLE WorkstationDoneEvent; HANDLE LogonDoneEvent; SERVICE_STATUS_HANDLE MsgrStatusHandle; SERVICE_STATUS_HANDLE SmfStaStatusHandle; SERVICE_STATUS_HANDLE LogonStatusHandle; // // Function Prototypes // DWORD MessingerStart ( DWORD argc, LPTSTR *argv ); DWORD SmerfStationStart ( DWORD argc, LPTSTR *argv ); DWORD LogonStart ( DWORD argc, LPTSTR *argv ); VOID MsgrCtrlHandler ( IN DWORD opcode ); VOID SmfStaCtrlHandler ( IN DWORD opcode ); VOID LogonCtrlHandler ( IN DWORD opcode ); DWORD ScReleasePrivilege( VOID ); DWORD ScGetPrivilege( IN DWORD numPrivileges, IN PULONG pulPrivileges ); /****************************************************************************/ VOID __cdecl main(VOID) { DWORD status; SERVICE_TABLE_ENTRY DispatchTable[] = { { TEXT("messinger"), MessingerStart }, { TEXT("smerfstation"), SmerfStationStart }, { TEXT("logon"), LogonStart }, { NULL, NULL } }; status = StartServiceCtrlDispatcher( DispatchTable); DbgPrint("The Service Process is Terminating....\n"); ExitProcess(0); } /****************************************************************************/ DWORD MessingerStart ( DWORD argc, LPTSTR *argv ) { DWORD status; DWORD i; DbgPrint(" [MESSINGER] Inside the Messinger Service Thread\n"); for (i=0; iPrivilegeCount = numPrivileges; for (i=0; iPrivileges[i].Luid = RtlConvertLongToLargeInteger( pulPrivileges[i]); pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; } // // Initialize Object Attribute Structure. // InitializeObjectAttributes(&Obja,NULL,0L,NULL,NULL); // // Initialize Security Quality Of Service Structure // SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); SecurityQofS.ImpersonationLevel = SecurityImpersonation; SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context SecurityQofS.EffectiveOnly = FALSE; Obja.SecurityQualityOfService = &SecurityQofS; // // Allocate storage for the structure that will hold the Previous State // information. // pPreviousState = (PTOKEN_PRIVILEGES) LocalAlloc( LMEM_FIXED, PRIVILEGE_BUF_SIZE ); if (pPreviousState == NULL) { status = GetLastError(); DbgPrint("ScGetPrivilege: LocalAlloc Failed %d\n", status); LocalFree((HLOCAL)pTokenPrivilege); return(status); } // // Open our own Token // ntStatus = NtOpenProcessToken( NtCurrentProcess(), TOKEN_DUPLICATE, &ourToken); if (!NT_SUCCESS(ntStatus)) { DbgPrint( "ScGetPrivilege: NtOpenThreadToken Failed " "%x \n", ntStatus); LocalFree((HLOCAL)pPreviousState); LocalFree((HLOCAL)pTokenPrivilege); return(RtlNtStatusToDosError(ntStatus)); } // // Duplicate that Token // ntStatus = NtDuplicateToken( ourToken, TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Obja, FALSE, // Duplicate the entire token TokenImpersonation, // TokenType &newToken); // Duplicate token if (!NT_SUCCESS(ntStatus)) { DbgPrint( "ScGetPrivilege: NtDuplicateToken Failed " "%x\n", ntStatus); LocalFree((HLOCAL)pPreviousState); LocalFree((HLOCAL)pTokenPrivilege); NtClose(ourToken); return(RtlNtStatusToDosError(ntStatus)); } // // Add new privileges // bufLen = PRIVILEGE_BUF_SIZE; ntStatus = NtAdjustPrivilegesToken( newToken, // TokenHandle FALSE, // DisableAllPrivileges pTokenPrivilege, // NewState bufLen, // bufferSize for previous state pPreviousState, // pointer to previous state info &returnLen); // numBytes required for buffer. if (ntStatus == STATUS_BUFFER_TOO_SMALL) { LocalFree((HLOCAL)pPreviousState); bufLen = returnLen; pPreviousState = (PTOKEN_PRIVILEGES) LocalAlloc( LMEM_FIXED, (UINT) bufLen ); ntStatus = NtAdjustPrivilegesToken( newToken, // TokenHandle FALSE, // DisableAllPrivileges pTokenPrivilege, // NewState bufLen, // bufferSize for previous state pPreviousState, // pointer to previous state info &returnLen); // numBytes required for buffer. } if (!NT_SUCCESS(ntStatus)) { DbgPrint( "ScGetPrivilege: NtAdjustPrivilegesToken Failed " "%x\n", ntStatus); LocalFree((HLOCAL)pPreviousState); LocalFree((HLOCAL)pTokenPrivilege); NtClose(ourToken); NtClose(newToken); return(RtlNtStatusToDosError(ntStatus)); } // // Begin impersonating with the new token // ntStatus = NtSetInformationThread( NtCurrentThread(), ThreadImpersonationToken, (PVOID)&newToken, (ULONG)sizeof(HANDLE)); if (!NT_SUCCESS(ntStatus)) { DbgPrint( "ScGetPrivilege: NtAdjustPrivilegesToken Failed " "%x\n", ntStatus); LocalFree((HLOCAL)pPreviousState); LocalFree((HLOCAL)pTokenPrivilege); NtClose(ourToken); NtClose(newToken); return(RtlNtStatusToDosError(ntStatus)); } LocalFree(pPreviousState); LocalFree(pTokenPrivilege); NtClose(ourToken); NtClose(newToken); return(NO_ERROR); } DWORD ScReleasePrivilege( VOID ) /*++ Routine Description: This function relinquishes privileges obtained by calling ScGetPrivilege(). Arguments: none Return Value: NO_ERROR - If the operation was completely successful. Otherwise, it returns mapped return codes from the various NT functions that are called. --*/ { NTSTATUS ntStatus; HANDLE NewToken; // // Revert To Self. // NewToken = NULL; ntStatus = NtSetInformationThread( NtCurrentThread(), ThreadImpersonationToken, (PVOID)&NewToken, (ULONG)sizeof(HANDLE)); if ( !NT_SUCCESS(ntStatus) ) { return(RtlNtStatusToDosError(ntStatus)); } return(NO_ERROR); }