1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Test for service process environment block 5 * PROGRAMMER: Hermes Belusca-Maito 6 */ 7 8 #include "precomp.h" 9 10 #include "svchlp.h" 11 12 13 /*** Service part of the test ***/ 14 15 static SERVICE_STATUS_HANDLE status_handle; 16 17 static void 18 report_service_status(DWORD dwCurrentState, 19 DWORD dwWin32ExitCode, 20 DWORD dwWaitHint) 21 { 22 BOOL res; 23 SERVICE_STATUS status; 24 25 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 26 status.dwCurrentState = dwCurrentState; 27 status.dwWin32ExitCode = dwWin32ExitCode; 28 status.dwWaitHint = dwWaitHint; 29 30 status.dwServiceSpecificExitCode = 0; 31 status.dwCheckPoint = 0; 32 33 if ( (dwCurrentState == SERVICE_START_PENDING) || 34 (dwCurrentState == SERVICE_STOP_PENDING) || 35 (dwCurrentState == SERVICE_STOPPED) ) 36 { 37 status.dwControlsAccepted = 0; 38 } 39 else 40 { 41 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; 42 } 43 44 #if 0 45 if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) ) 46 status.dwCheckPoint = 0; 47 else 48 status.dwCheckPoint = dwCheckPoint++; 49 #endif 50 51 res = SetServiceStatus(status_handle, &status); 52 service_ok(res, "SetServiceStatus(%d) failed: %lu\n", dwCurrentState, GetLastError()); 53 } 54 55 static VOID WINAPI service_handler(DWORD ctrl) 56 { 57 switch(ctrl) 58 { 59 case SERVICE_CONTROL_STOP: 60 case SERVICE_CONTROL_SHUTDOWN: 61 report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0); 62 default: 63 report_service_status(SERVICE_RUNNING, NO_ERROR, 0); 64 } 65 } 66 67 static void WINAPI 68 service_main(DWORD dwArgc, LPWSTR* lpszArgv) 69 { 70 // SERVICE_STATUS_HANDLE status_handle; 71 LPWSTR lpEnvironment, lpEnvStr; 72 DWORD dwSize; 73 PTEB Teb; 74 75 UNREFERENCED_PARAMETER(dwArgc); 76 UNREFERENCED_PARAMETER(lpszArgv); 77 78 /* Register our service for control (lpszArgv[0] holds the service name) */ 79 status_handle = RegisterServiceCtrlHandlerW(lpszArgv[0], service_handler); 80 service_ok(status_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError()); 81 if (!status_handle) 82 return; 83 84 /* Report SERVICE_RUNNING status */ 85 report_service_status(SERVICE_RUNNING, NO_ERROR, 4000); 86 87 /* Display our current environment for informative purposes */ 88 lpEnvironment = GetEnvironmentStringsW(); 89 lpEnvStr = lpEnvironment; 90 while (*lpEnvStr) 91 { 92 service_trace("%S\n", lpEnvStr); 93 lpEnvStr += wcslen(lpEnvStr) + 1; 94 } 95 FreeEnvironmentStringsW(lpEnvironment); 96 97 /* Check the presence of the user-related environment variables */ 98 dwSize = GetEnvironmentVariableW(L"ALLUSERSPROFILE", NULL, 0); 99 service_ok(dwSize != 0, "ALLUSERSPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError()); 100 dwSize = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0); 101 service_ok(dwSize != 0, "USERPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError()); 102 #if 0 // May not always exist 103 dwSize = GetEnvironmentVariableW(L"USERNAME", NULL, 0); 104 service_ok(dwSize != 0, "USERNAME envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError()); 105 #endif 106 107 Teb = NtCurrentTeb(); 108 service_ok(Teb->SubProcessTag != 0, "SubProcessTag is not defined!\n"); 109 if (Teb->SubProcessTag != 0) 110 { 111 ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID) = (PVOID)GetProcAddress(GetModuleHandle("advapi32.dll"), "I_QueryTagInformation"); 112 if (_I_QueryTagInformation != NULL) 113 { 114 /* IN/OUT parameter structure for I_QueryTagInformation() function 115 * See: https://wj32.org/wp/2010/03/30/howto-use-i_querytaginformation/ 116 * See: https://github.com/processhacker/processhacker/blob/master/phnt/include/subprocesstag.h 117 */ 118 struct 119 { 120 ULONG ProcessId; 121 PVOID ServiceTag; 122 ULONG TagType; 123 PWSTR Buffer; 124 } ServiceQuery; 125 126 /* Set our input parameters */ 127 ServiceQuery.ProcessId = GetCurrentProcessId(); 128 ServiceQuery.ServiceTag = Teb->SubProcessTag; 129 ServiceQuery.TagType = 0; 130 ServiceQuery.Buffer = NULL; 131 /* Call ADVAPI32 to query the correctness of our tag */ 132 _I_QueryTagInformation(NULL, 1, &ServiceQuery); 133 134 /* If buffer is not NULL, call succeed */ 135 if (ServiceQuery.Buffer != NULL) 136 { 137 /* It should match our service name */ 138 service_ok(wcscmp(lpszArgv[0], ServiceQuery.Buffer) == 0, "Mismatching info: %S - %S\n", lpszArgv[0], ServiceQuery.Buffer); 139 service_ok(ServiceQuery.TagType == 1, "Invalid tag type: %x\n", ServiceQuery.TagType); 140 LocalFree(ServiceQuery.Buffer); 141 } 142 } 143 } 144 145 /* Work is done */ 146 report_service_status(SERVICE_STOPPED, NO_ERROR, 0); 147 } 148 149 static BOOL start_service(PCSTR service_nameA, PCWSTR service_nameW) 150 { 151 BOOL res; 152 153 SERVICE_TABLE_ENTRYW servtbl[] = 154 { 155 { (PWSTR)service_nameW, service_main }, 156 { NULL, NULL } 157 }; 158 159 res = StartServiceCtrlDispatcherW(servtbl); 160 service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError()); 161 return res; 162 } 163 164 165 /*** Tester part of the test ***/ 166 167 static void 168 my_test_server(PCSTR service_nameA, 169 PCWSTR service_nameW, 170 void *param) 171 { 172 BOOL res; 173 SC_HANDLE hSC = NULL; 174 SC_HANDLE hService = NULL; 175 SERVICE_STATUS ServiceStatus; 176 177 /* Open the SCM */ 178 hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); 179 if (!hSC) 180 { 181 skip("OpenSCManagerW failed with error %lu!\n", GetLastError()); 182 return; 183 } 184 185 /* First create ourselves as a service running in the default LocalSystem account */ 186 hService = register_service_exW(hSC, L"ServiceEnv", service_nameW, NULL, 187 SERVICE_ALL_ACCESS, 188 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, 189 SERVICE_DEMAND_START, 190 SERVICE_ERROR_IGNORE, 191 NULL, NULL, NULL, 192 NULL, NULL); 193 if (!hService) 194 { 195 skip("CreateServiceW failed with error %lu!\n", GetLastError()); 196 goto Cleanup; 197 } 198 199 /* Start it */ 200 if (!StartServiceW(hService, 0, NULL)) 201 { 202 skip("StartServiceW failed with error %lu!\n", GetLastError()); 203 goto Cleanup; 204 } 205 206 /* Wait for the service to stop by itself */ 207 do 208 { 209 Sleep(100); 210 ZeroMemory(&ServiceStatus, sizeof(ServiceStatus)); 211 res = QueryServiceStatus(hService, &ServiceStatus); 212 } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED); 213 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError()); 214 ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState); 215 216 /* Be sure the service is really stopped */ 217 res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); 218 if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED && 219 ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && 220 GetLastError() != ERROR_SERVICE_NOT_ACTIVE) 221 { 222 skip("ControlService failed with error %lu!\n", GetLastError()); 223 goto Cleanup; 224 } 225 226 #if 0 227 trace("Service stopped. Going to restart it...\n"); 228 229 /* Now change the service configuration to make it start under the NetworkService account */ 230 if (!ChangeServiceConfigW(hService, 231 SERVICE_NO_CHANGE, 232 SERVICE_NO_CHANGE, 233 SERVICE_NO_CHANGE, 234 NULL, NULL, NULL, NULL, 235 L"NT AUTHORITY\\NetworkService", L"", 236 NULL)) 237 { 238 skip("ChangeServiceConfigW failed with error %lu!\n", GetLastError()); 239 goto Cleanup; 240 } 241 242 /* Start it */ 243 if (!StartServiceW(hService, 0, NULL)) 244 { 245 skip("StartServiceW failed with error %lu!\n", GetLastError()); 246 goto Cleanup; 247 } 248 249 /* Wait for the service to stop by itself */ 250 do 251 { 252 Sleep(100); 253 ZeroMemory(&ServiceStatus, sizeof(ServiceStatus)); 254 res = QueryServiceStatus(hService, &ServiceStatus); 255 } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED); 256 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError()); 257 ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState); 258 259 /* Be sure the service is really stopped */ 260 res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); 261 if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED && 262 ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && 263 GetLastError() != ERROR_SERVICE_NOT_ACTIVE) 264 { 265 skip("ControlService failed with error %lu!\n", GetLastError()); 266 goto Cleanup; 267 } 268 #endif 269 270 Cleanup: 271 if (hService) 272 { 273 res = DeleteService(hService); 274 ok(res, "DeleteService failed: %lu\n", GetLastError()); 275 CloseServiceHandle(hService); 276 } 277 278 if (hSC) 279 CloseServiceHandle(hSC); 280 } 281 282 START_TEST(ServiceEnv) 283 { 284 int argc; 285 char** argv; 286 PTEB Teb; 287 288 /* Check whether this test is started as a separated service process */ 289 argc = winetest_get_mainargs(&argv); 290 if (argc >= 3) 291 { 292 service_process(start_service, argc, argv); 293 return; 294 } 295 296 Teb = NtCurrentTeb(); 297 ok(Teb->SubProcessTag == 0, "SubProcessTag is defined: %p\n", Teb->SubProcessTag); 298 299 /* We are started as the real test */ 300 test_runner(my_test_server, NULL); 301 // trace("Returned from test_runner\n"); 302 } 303