Em sex., 13 de ago. de 2021 às 10:03, Andres Freund <and...@anarazel.de> escreveu:
> Hi, > > Magnus, Michael, Anyone - I'd appreciate a look. > > On 2021-03-05 12:55:37 -0800, Andres Freund wrote: > > > After fighting with a windows VM for a bit (ugh), it turns out that > yes, > > > there is stderr, but that fileno(stderr) returns -2, and > > > GetStdHandle(STD_ERROR_HANDLE) returns NULL (not INVALID_HANDLE_VALUE). > > > > > > The complexity however is that while that's true for pg_ctl within > > > pgwin32_ServiceMain: > > > checking what stderr=00007FF8687DFCB0 is (handle: 0, fileno=-2) > > > but not for postmaster or backends > > > WARNING: 01000: checking what stderr=00007FF880F5FCB0 is (handle: 92, > fileno=2) > > > > > > which makes sense in a way, because we don't tell CreateProcessAsUser() > > > that it should pass stdin/out/err down (which then seems to magically > > > get access to the "topmost" console applications output - damn, this > > > stuff is weird). > > > > That part is not too hard to address - it seems we only need to do that > > in pg_ctl pgwin32_doRunAsService(). It seems that the > > stdin/stderr/stdout being set to invalid will then be passed down to > > postmaster children. > > > > https://docs.microsoft.com/en-us/windows/console/getstdhandle > > "If an application does not have associated standard handles, such as a > > service running on an interactive desktop, and has not redirected them, > > the return value is NULL." > > > > There does seem to be some difference between what services get as std* > > - GetStdHandle() returns NULL, and what explicitly passing down invalid > > handles to postmaster does - GetStdHandle() returns > > INVALID_HANDLE_VALUE. But passing down NULL rather than > > INVALID_HANDLE_VALUE to postmaster seems to lead to postmaster > > re-opening console buffers. > > > > Patch attached. > > > I'd like to commit something to address this issue to master soon - it > > allows us to run a lot more tests in cirrus-ci... But probably not > > backpatch it [yet] - there've not really been field complaints, and who > > knows if there end up being some unintentional side-effects... > > Because it'd allow us to run more tests as part of cfbot and other CI > efforts, I'd like to push this forward. So I'm planning to commit this > to master soon-ish, unless somebody wants to take this over? I'm really > not a windows person... > Hi Andres, I found this function on the web, from OpenSSL, but I haven't tested it. I think that there is one more way to test if a service is running (SECURITY_INTERACTIVE_RID). Can you test on a Windows VM? If this works I can elaborate a bit. Attached. regards, Ranier Vilela
int pgwin32_is_service(void) { static int _is_service = -1; HANDLE hProcessToken = NULL; DWORD groupLength = 64; PTOKEN_GROUPS groupInfo; SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY; PSID InteractiveSid = NULL; PSID ServiceSid = NULL; DWORD i; /* Only check the first time */ if (_is_service != -1) return _is_service; _is_service = 0; groupInfo = (PTOKEN_GROUPS) LocalAlloc(0, groupLength); if (groupInfo == NULL) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken)) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo, groupLength, &groupLength)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } LocalFree(groupInfo); groupInfo = NULL; groupInfo = (PTOKEN_GROUPS) LocalAlloc(0, groupLength); if (groupInfo == NULL) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo, groupLength, &groupLength)) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } } // // We now know the groups associated with this token. We want to look to see if // the interactive group is active in the token, and if so, we know that // this is an interactive process. // // We also look for the "service" SID, and if it's present, we know we're a service. // // The service SID will be present iff the service is running in a // user account (and was invoked by the service controller). // if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID, 0, 0, 0, 0, 0, 0, 0, &InteractiveSid)) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &ServiceSid)) { fprintf(stderr, "could not get SID for local system account\n"); goto clean; } for (i = 0; i < groupInfo->GroupCount; i += 1) { SID_AND_ATTRIBUTES sanda = groupInfo->Groups[i]; PSID Sid = sanda.Sid; // // Check to see if the group we're looking at is one of // the 2 groups we're interested in. // if (EqualSid(Sid, InteractiveSid)) { // // This process has the Interactive SID in its // token. This means that the process is running as // an EXE. // goto clean; } else if (EqualSid(Sid, ServiceSid)) { // // This process has the Service SID in its // token. This means that the process is running as // a service running in a user account. // _is_service = 1; goto clean; } } // // Neither Interactive or Service was present in the current users token, // This implies that the process is running as a service, most likely // running as LocalSystem. // _is_service = 1; clean: if (InteractiveSid) FreeSid(InteractiveSid); if (ServiceSid) FreeSid(ServiceSid); if (groupInfo) LocalFree(groupInfo); if (hProcessToken) CloseHandle(hProcessToken); return _is_service; }