1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
10
* Sun Industry Standards Source License Version 1.2
11
* =================================================
12
* The contents of this file are subject to the Sun Industry Standards
13
* Source License Version 1.2 (the "License"); You may not use this file
14
* except in compliance with the License. You may obtain a copy of the
15
* License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
17
* Software provided under this License is provided on an "AS IS" basis,
18
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
19
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
20
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
21
* See the License for the specific provisions governing your rights and
22
* obligations concerning the Software.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2001 by Sun Microsystems, Inc.
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
38
#include <sys/types.h>
49
#include "SGE_Helper_Service.h"
50
#include "Communication.h"
52
#define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
53
DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | \
54
DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
55
DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
57
#define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \
58
WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | \
59
WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | \
60
WINSTA_READSCREEN | STANDARD_RIGHTS_REQUIRED)
62
#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | \
65
// function forward declarations
66
static BOOL GetLogonSID(HANDLE hToken, PSID &pSid);
67
static void FreeLogonSID(PSID &pSid);
68
static BOOL AddAceToWindowStation(HWINSTA hWinsta, PSID pSid);
69
static BOOL AddAceToDesktop(HDESK hDesk, PSID pSid);
70
static BOOL RemoveAceFromWindowStation(HWINSTA hWinsta, PSID pSid);
71
static BOOL RemoveAceFromDesktop(HDESK hDesk, PSID pSid);
73
static BOOL GetJobStartModeFromConf(char **conf, int nconf);
74
static BOOL GetModeFromEnv(const char *mode, char **env, int nenv);
75
static void WriteEnvToFile(char *pszEnv, char *pszFile);
76
static DWORD RedirectStdHandles(const C_Job& Job, HANDLE &hStdout, HANDLE &hStderr);
79
extern C_JobList g_JobList;
80
extern C_Communication g_Communication;
81
extern HANDLE g_hWinstaACLMutex;
82
extern HANDLE g_hDeskACLMutex;
84
/****** JobStarterThread() ****************************************************
86
* JobStarterThread() -- starting point of job starter thread
89
* DWORD WINAPI JobStarterThread(LPVOID lpParameter)
92
* This is the starting point for the job starter thread
93
* It searches a job with js_Received from the job list and tries to
94
* start it. It sends a response to the sge_shepherd if job was
95
* successfully or unsuccessfully started.
98
* LPVOID lpParameter - unused
101
* DWORD - exit status of the job starter thread
103
* >0: GetLastError() value
106
*******************************************************************************/
107
DWORD WINAPI JobStarterThread(LPVOID lpParameter)
112
// lock access to job list
113
CSingleLock singleLock(&g_JobList.m_JobListMutex);
116
// get job from job list that still is to be executed
117
pJob = g_JobList.GetFirstJobInReceivedState();
119
pJob->m_JobStatus = js_ToBeStarted;
122
// unlock access to job list
127
ret = StartJob(*pJob);
129
// send exit code to sge_shepherd
130
g_Communication.SendExitStatus(*pJob);
131
g_Communication.ShutdownSocket(&(pJob->m_comm_sock));
136
/****** StartJob() ************************************************************
138
* StartJob() -- starts the job
141
* DWORD StartJob(C_Job &Job)
144
* Gives job user full access to the visible desktop, starts the job
145
* waits for job end, reads usage data, withdraws access to visible
146
* desktop from job user.
149
* C_Job &Job - all informations about the job that is to be started
152
* DWORD - exit status of the job starter thread
154
* >0: GetLastError() value
157
*******************************************************************************/
158
DWORD StartJob(C_Job &Job)
161
PROCESS_INFORMATION pi;
163
HANDLE hToken = INVALID_HANDLE_VALUE;
164
HANDLE hStdout = INVALID_HANDLE_VALUE;
165
HANDLE hStderr = INVALID_HANDLE_VALUE;
167
char *pszCmdLine = NULL;
169
char szErrorPart[1024];
171
DWORD dwError = ERROR_SUCCESS;
172
HWINSTA hWinstaSave = NULL;
173
HWINSTA hWinsta = NULL;
176
BOOL bResult = FALSE;
177
char *pFileName = NULL;
178
const char *pszCurDir = NULL;
180
BOOL bBackgndMode = FALSE;
181
CSingleLock singleLock(&g_JobList.m_JobListMutex);
183
if(GetJobStartModeFromConf(Job.conf, Job.nconf) == FALSE) {
184
Job.m_JobStatus = js_Failed;
188
// Build environment as local Administrator
189
Job.BuildEnvironment(pszEnv);
190
Job.BuildCommandLine(pszCmdLine);
191
pszCurDir = Job.GetConfValue("cwd");
193
ZeroMemory(&si, sizeof(si));
194
ZeroMemory(&pi, sizeof(pi));
195
ZeroMemory(szErrorPart, sizeof(szErrorPart));
201
LOGON32_LOGON_INTERACTIVE,
202
LOGON32_PROVIDER_DEFAULT,
204
sprintf(szErrorPart, "LogonUser failed:");
208
bBackgndMode = GetModeFromEnv("SGE_BACKGND_MODE", Job.env, Job.nenv);
209
if(bBackgndMode == FALSE) {
210
// Save a handle to the caller's current window station.
211
if((hWinstaSave = GetProcessWindowStation()) == NULL) {
212
sprintf(szErrorPart, "GetProcessWindowStation failed:");
216
// Get a handle to the interactive window station.
217
hWinsta = OpenWindowStation(
218
"winsta0", // the interactive window station
219
FALSE, // handle is not inheritable
220
READ_CONTROL | WRITE_DAC); // rights to read/write the DACL
222
if(hWinsta == NULL) {
223
sprintf(szErrorPart, "OpenWindowStation failed:");
227
// To get the correct default desktop, set the caller's
228
// window station to the interactive window station.
229
if(!SetProcessWindowStation(hWinsta)) {
230
sprintf(szErrorPart, "SetProcessWindowStation(hWinsta) failed:");
234
// Get a handle to the interactive desktop.
236
"default", // the interactive window station
237
0, // no interaction with other desktop processes
238
FALSE, // handle is not inheritable
239
READ_CONTROL | // request the rights to read and write the DACL
241
DESKTOP_WRITEOBJECTS |
242
DESKTOP_READOBJECTS);
244
// Restore the caller's window station.
245
if(!SetProcessWindowStation(hWinstaSave)) {
246
sprintf(szErrorPart, "SetProcessWindowStation(hWinstaSave) failed:");
251
sprintf(szErrorPart, "OpenDesktop failed:");
255
// Get the SID for the client's logon session.
256
if(!GetLogonSID(hToken, pSid)) {
257
sprintf(szErrorPart, "GetLogonSID failed:");
261
// Allow logon SID full access to interactive window station.
262
if(!AddAceToWindowStation(hWinsta, pSid)) {
263
sprintf(szErrorPart, "AddAceToWindowStation failed:");
267
// Allow logon SID full access to interactive desktop.
268
if(!AddAceToDesktop(hDesk, pSid)) {
269
sprintf(szErrorPart, "AddAceToDesktop failed:");
274
// Impersonate client to ensure access to executable file.
275
if(!ImpersonateLoggedOnUser(hToken)) {
276
sprintf(szErrorPart, "ImpersonateLoggedOnUser failed:");
280
// Redirect stdout and stderr
281
if(RedirectStdHandles(Job, hStdout, hStderr)!=0) {
282
sprintf(szErrorPart, "Redirecting File Handles failed:");
286
si.cb = sizeof(STARTUPINFO);
287
si.dwFlags |= STARTF_USESTDHANDLES;
288
si.hStdOutput = hStdout;
289
si.hStdError = hStderr;
290
si.wShowWindow = SW_SHOW;
292
if(bBackgndMode == TRUE) {
295
si.lpDesktop = "WinSta0\\Default";
298
// To avoid a race condition with a signal here, lock Job list, check if
299
// this job has been killed in the meanwhile. If job is not locked, start
300
// it (job may not get killed in the meanwhile, because list is locked),
301
// but unlock before the blocking wait. After the job has been started,
302
// killing it will not lead to unexpected resultst.
305
if(Job.m_JobStatus == js_Deleted) {
310
Job.m_hJobObject = CreateJobObject(NULL, NULL);
312
// Launch the process in the client's logon session.
313
bResult = CreateProcessAsUser(hToken,
319
NORMAL_PRIORITY_CLASS,//|CREATE_NO_WINDOW,//|CREATE_NEW_CONSOLE,
326
dwError = GetLastError();
329
sprintf(szErrorPart, "CreateProcessAsUser failed:");
332
SetLastError(dwError);
336
AssignProcessToJobObject(Job.m_hJobObject, pi.hProcess);
338
// End impersonation of client.
341
Job.m_JobStatus = js_Started;
342
Job.m_hProcess = pi.hProcess;
344
// unlock access to job list
347
// Wait blocking for job end
348
if(bResult && pi.hProcess != INVALID_HANDLE_VALUE) {
349
WriteToLogFile("Waiting for job end.");
350
dwWait = WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);
351
if(dwWait==WAIT_OBJECT_0) {
352
Job.StoreUsage(pi.hProcess);
354
WriteToLogFile("Job ended.");
355
CloseHandle(pi.hProcess);
356
CloseHandle(Job.m_hJobObject);
357
Job.m_hProcess = INVALID_HANDLE_VALUE;
358
Job.m_hJobObject = INVALID_HANDLE_VALUE;
359
Job.m_JobStatus = js_Finished;
361
if(pi.hThread != INVALID_HANDLE_VALUE) {
362
CloseHandle(pi.hThread);
365
if(bBackgndMode == FALSE) {
366
// Disallow logon SID full access to interactive desktop.
367
if(!RemoveAceFromDesktop(hDesk, pSid)) {
368
sprintf(szErrorPart, "RemoveAceFromDesktop failed:");
371
// Disallow logon SID full access to interactive window station.
372
if(!RemoveAceFromWindowStation(hWinsta, pSid)) {
373
sprintf(szErrorPart, "RemoveAceFromWindowStation failed:");
383
char szLastError[501];
385
dwError = GetLastError();
388
// FormatMessage doesn't provide an error message for errno=193
389
// The table of System Errors from the MSDN Libary tells us:
390
// 193 Is not a valid application. ERROR_BAD_EXE_FORMAT
391
strcpy(szLastError, "Is not a valid application.");
393
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
394
NULL, dwError, 0, szLastError, 500, NULL);
397
if(strlen(szLastError) > 0) {
398
if(szLastError[strlen(szLastError)-2] == '\r') {
399
szLastError[strlen(szLastError)-2] = '\0';
402
strcpy(szLastError, "(no error message available from system)");
405
sprintf(szError, "%s %s (errno=%d)",
409
WriteToLogFile(szError);
411
Job.szError = strdup(szError);
412
Job.m_JobStatus = js_Failed;
415
if(hStdout != INVALID_HANDLE_VALUE) {
416
CloseHandle(hStdout);
418
if(hStderr != INVALID_HANDLE_VALUE) {
419
CloseHandle(hStderr);
422
if(hWinstaSave != NULL) {
423
SetProcessWindowStation(hWinstaSave);
426
// Free the buffer for the logon SID.
431
// Close the handles to the interactive window station and desktop.
432
if(hWinsta != NULL) {
433
CloseWindowStation(hWinsta);
438
// Close the handle to the client's access token.
439
if(hToken != INVALID_HANDLE_VALUE) {
448
/****** GetLogonSID() *********************************************************
450
* GetLogonSID() -- retrieve SID of logged on user
453
* static BOOL GetLogonSID(HANDLE hToken, PSID &pSid)
456
* Retrieves the SID of the logged on user represented by the logon
460
* HANDLE hToken - token of the logged on user
463
* PSID &pSid - SID of the logged on user
466
* BOOL - true if SID could be retrieved, false if not
469
*******************************************************************************/
470
static BOOL GetLogonSID(HANDLE hToken, PSID &pSid)
475
PTOKEN_GROUPS ptg = NULL;
477
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
478
if(!GetTokenInformation(hToken, TokenGroups,
479
(LPVOID)ptg, 0, &dwLength)) {
480
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
483
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
484
HEAP_ZERO_MEMORY, dwLength);
490
// Get the token group information from the access token.
491
if(!GetTokenInformation(hToken, TokenGroups,
492
(LPVOID)ptg, dwLength, &dwLength)) {
496
// Loop through the groups to find the logon SID.
497
for(dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
498
if((ptg->Groups[dwIndex].Attributes&SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID) {
499
// Found the logon SID; make a copy of it.
500
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
501
pSid = (PSID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
506
if(!CopySid(dwLength, pSid, ptg->Groups[dwIndex].Sid)) {
507
HeapFree(GetProcessHeap(), 0, (LPVOID)pSid);
516
// Free the buffer for the token groups.
518
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
523
/****** FreeLogonSID() ****************************************************++++
525
* FreeLogonSID() -- frees the buffer of the SID
528
* static void FreeLogonSID(PSID &pSid)
531
* Frees the buffer of the SID allocated by GetLogonSID()
534
* PSID &pSid - the SID to be freed.
540
*******************************************************************************/
541
static void FreeLogonSID(PSID &pSid)
543
HeapFree(GetProcessHeap(), 0, (LPVOID)pSid);
546
/****** AddAceToWindowStation() ************************************************
548
* AddAceToWindowStation() -- adds the ACE of the job user to the ACL of the
549
* visible window station.
552
* static BOOL AddAceToWindowStation(HWINSTA hWinsta, PSID pSid)
555
* Adds the ACE (Access Control Entry) of the job user to the ACL
556
* (Access Control List) of the visible window station.
559
* HWINSTA hWinsta - Handle of the visible window station
560
* PSID pSid - SID (Security Identifier) of the job user
563
* BOOL - true if adding succeeded, false if it failed
566
*******************************************************************************/
567
static BOOL AddAceToWindowStation(HWINSTA hWinsta, PSID pSid)
569
ACCESS_ALLOWED_ACE *pAce;
570
ACL_SIZE_INFORMATION aclSizeInfo;
576
DWORD dwSdSizeNeeded;
579
PSECURITY_DESCRIPTOR pSd = NULL;
580
PSECURITY_DESCRIPTOR pSdNew = NULL;
582
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
585
if(WaitForSingleObject(g_hWinstaACLMutex, INFINITE) == WAIT_OBJECT_0) {
588
// Obtain the DACL for the window station.
589
if(!GetUserObjectSecurity(hWinsta, &si, pSd, dwSidSize, &dwSdSizeNeeded)) {
590
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
591
pSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
592
HEAP_ZERO_MEMORY, dwSdSizeNeeded);
599
pSdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
600
HEAP_ZERO_MEMORY, dwSdSizeNeeded);
606
dwSidSize = dwSdSizeNeeded;
607
if(!GetUserObjectSecurity(hWinsta, &si, pSd, dwSidSize, &dwSdSizeNeeded)) {
614
// Create a new DACL.
615
if(!InitializeSecurityDescriptor(pSdNew, SECURITY_DESCRIPTOR_REVISION)) {
619
// Get the DACL from the security descriptor.
620
if(!GetSecurityDescriptorDacl(pSd, &bDaclPresent, &pAcl, &bDaclExist)) {
624
// Initialize the ACL.
625
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
626
aclSizeInfo.AclBytesInUse = sizeof(ACL);
628
// Call only if the DACL is not NULL.
630
// get the file ACL size info
631
if(!GetAclInformation(pAcl, (LPVOID)&aclSizeInfo,
632
sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
637
// Compute the size of the new ACL.
638
dwNewAclSize = aclSizeInfo.AclBytesInUse
639
+ (2*sizeof(ACCESS_ALLOWED_ACE))
640
+ (2*GetLengthSid(pSid)) - (2*sizeof(DWORD));
642
// Allocate memory for the new ACL.
643
pNewAcl = (PACL)HeapAlloc(GetProcessHeap(),
644
HEAP_ZERO_MEMORY, dwNewAclSize);
646
if(pNewAcl == NULL) {
650
// Initialize the new DACL.
651
if(!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) {
655
// If DACL is present, copy it to a new DACL.
657
// Copy the ACEs to the new ACL.
658
if(aclSizeInfo.AceCount) {
659
for(i=0; i < aclSizeInfo.AceCount; i++) {
660
if(!GetAce(pAcl, i, &pTempAce)) {
664
// Add the ACE to the new ACL.
665
if(!AddAce(pNewAcl, ACL_REVISION, MAXDWORD,
666
pTempAce, ((PACE_HEADER)pTempAce)->AceSize)) {
673
// Add the first ACE to the window station.
674
pAce = (ACCESS_ALLOWED_ACE *)HeapAlloc(
677
sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) -
683
pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
684
pAce->Header.AceFlags = CONTAINER_INHERIT_ACE |
685
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
686
pAce->Header.AceSize = (WORD)(sizeof(ACCESS_ALLOWED_ACE) +
687
GetLengthSid(pSid) - sizeof(DWORD));
688
pAce->Mask = GENERIC_ACCESS;
690
if (!CopySid(GetLengthSid(pSid), &pAce->SidStart, pSid))
698
pAce->Header.AceSize)
702
// Add the second ACE to the window station.
703
pAce->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
704
pAce->Mask = WINSTA_ALL;
711
pAce->Header.AceSize)
715
// Set a new DACL for the security descriptor.
716
if (!SetSecurityDescriptorDacl(
724
// Set the new security descriptor for the window station.
725
if(!SetUserObjectSecurity(hWinsta, &si, pSdNew)) {
727
char szLastError[501];
729
dwError = GetLastError();
730
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, szLastError, 500, NULL);
738
// Free the allocated buffers.
741
HeapFree(GetProcessHeap(), 0, (LPVOID)pAce);
744
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
747
HeapFree(GetProcessHeap(), 0, (LPVOID)pSd);
750
HeapFree(GetProcessHeap(), 0, (LPVOID)pSdNew);
752
ReleaseMutex(g_hWinstaACLMutex);
757
/****** AddAceToDesktop() ******************************************************
759
* AddAceToDesktop() -- adds the ACE of the job user to the ACL of the
763
* static BOOL AddAceToDesktop(HDESK hDesk, PSID pSid)
766
* Adds the ACE (Access Control Entry) of the job user to the ACL
767
* (Access Control List) of the visible desktop.
770
* HDESK hDesk - Handle of the visible desktop
771
* PSID pSid - SID (Security Identifier) of the job user
774
* BOOL - true if adding succeeded, false if it failed
777
*******************************************************************************/
778
static BOOL AddAceToDesktop(HDESK hDesk, PSID pSid)
780
ACL_SIZE_INFORMATION aclSizeInfo;
786
DWORD dwSdSizeNeeded;
790
PSECURITY_DESCRIPTOR pSd = NULL;
791
PSECURITY_DESCRIPTOR pSdNew = NULL;
792
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
795
if(WaitForSingleObject(g_hDeskACLMutex, INFINITE) == WAIT_OBJECT_0) {
798
// Obtain the security descriptor for the desktop object.
799
if(!GetUserObjectSecurity(hDesk, &si, pSd, dwSidSize, &dwSdSizeNeeded)) {
800
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
801
pSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
802
HEAP_ZERO_MEMORY, dwSdSizeNeeded);
807
pSdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
808
HEAP_ZERO_MEMORY, dwSdSizeNeeded);
813
dwSidSize = dwSdSizeNeeded;
814
if(!GetUserObjectSecurity(hDesk, &si, pSd,
815
dwSidSize, &dwSdSizeNeeded)) {
823
// Create a new security descriptor.
824
if(!InitializeSecurityDescriptor(pSdNew, SECURITY_DESCRIPTOR_REVISION)) {
828
// Obtain the DACL from the security descriptor.
829
if (!GetSecurityDescriptorDacl(pSd, &bDaclPresent, &pAcl, &bDaclExist)) {
834
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
835
aclSizeInfo.AclBytesInUse = sizeof(ACL);
838
// Determine the size of the ACL information.
839
if (!GetAclInformation(pAcl, (LPVOID)&aclSizeInfo,
840
sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
845
// Compute the size of the new ACL and allocate buffer
846
dwNewAclSize = aclSizeInfo.AclBytesInUse
847
+ sizeof(ACCESS_ALLOWED_ACE)
848
+ GetLengthSid(pSid) - sizeof(DWORD);
850
pNewAcl = (PACL)HeapAlloc(GetProcessHeap(),
851
HEAP_ZERO_MEMORY, dwNewAclSize);
853
if(pNewAcl == NULL) {
857
if(!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) {
861
// If DACL is present, copy it to a new DACL.
863
// Copy the ACEs to the new ACL.
864
if(aclSizeInfo.AceCount) {
865
for(i=0; i < aclSizeInfo.AceCount; i++) {
867
if(!GetAce(pAcl, i, &pTempAce)) {
871
// Add the ACE to the new ACL.
872
if(!AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pTempAce,
873
((PACE_HEADER)pTempAce)->AceSize)) {
880
// Add ACE to the DACL, set new DACL to the new security descriptor,
881
// set new security descriptor for the desktop object.
882
if(!AddAccessAllowedAce(pNewAcl, ACL_REVISION, DESKTOP_ALL, pSid)) {
885
if(!SetSecurityDescriptorDacl(pSdNew, TRUE, pNewAcl, FALSE)) {
888
if(!SetUserObjectSecurity(hDesk, &si, pSdNew)) {
896
if(pNewAcl != NULL) {
897
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
901
HeapFree(GetProcessHeap(), 0, (LPVOID)pSd);
905
HeapFree(GetProcessHeap(), 0, (LPVOID)pSdNew);
908
ReleaseMutex(g_hDeskACLMutex);
913
/****** RemoveAceFromWindowStation() ******************************************
915
* RemoveAceFromWindowStation() -- removes the ACE of the job user from the
916
* ACL of the visible window station.
919
* static BOOL RemoveAceFromWindowStation(HWINSTA hWinsta, PSID pSid)
922
* Removes the ACE (Access Control Entry) of the job user from the ACL
923
* (Access Control List) of the visible window station.
926
* HWINSTA hWinsta - Handle of the visible window station
927
* PSID pSid - SID (Security Identifier) of the job user
930
* BOOL - true if removing succeeded, false if it failed
933
*******************************************************************************/
934
static BOOL RemoveAceFromWindowStation(HWINSTA hWinsta, PSID pSid)
936
SECURITY_DESCRIPTOR *pSD = NULL;
938
BOOL bDaclPresent = TRUE;
939
BOOL bDaclDefaulted = FALSE;
941
DWORD SDLengthNeeded = 0;
944
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
950
if(WaitForSingleObject(g_hWinstaACLMutex, INFINITE) == WAIT_OBJECT_0) {
953
// Obtain DACL from Windows station, search for ACE, remove ACE from DACL
954
bSecRet = GetUserObjectSecurity(hWinsta, &si, pSD, SDLength, &SDLengthNeeded);
956
pSD = (SECURITY_DESCRIPTOR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SDLengthNeeded);
958
bSecRet = GetUserObjectSecurity(hWinsta, &si, pSD, SDLengthNeeded, &SDLengthNeeded);
959
bSecRet = GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pWinstaDacl, &bDaclDefaulted);
961
for(int i=pWinstaDacl->AceCount-1; i>=0; i--) {
962
bSecRet = GetAce(pWinstaDacl, i, &pWinstaAce);
963
if(((ACCESS_ALLOWED_ACE*)pWinstaAce)->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
964
pListSid = (PSID)&(((ACCESS_ALLOWED_ACE*)pWinstaAce)->SidStart);
966
bSecRet = IsValidSid(pSid);
967
bSecRet = IsValidSid(pListSid);
968
DWORD dwSidLength = GetLengthSid(pSid);
969
DWORD dwListSidLength = GetLengthSid(pListSid);
971
for(DWORD j=0; j<dwSidLength && j<dwListSidLength; j++) {
972
if(*((BYTE*)pListSid+j) != *((BYTE*)pSid+j)) {
978
DeleteAce(pWinstaDacl, i);
986
SetUserObjectSecurity(hWinsta, &si, pSD);
992
HeapFree(GetProcessHeap(), 0, (LPVOID)pSD);
996
ReleaseMutex(g_hWinstaACLMutex);
1001
/****** RemoveAceFromDesktop() ************************************************
1003
* RemoveAceFromDesktop() -- removes the ACE of the job user from the
1004
* ACL of the visible desktop
1007
* static BOOL RemoveAceFromDesktop(HDESK hDesk, PSID pSid)
1010
* Removes the ACE (Access Control Entry) of the job user from the ACL
1011
* (Access Control List) of the visible desktop
1014
* HDESK hDesk - Handle of the visible desktop
1015
* PSID pSid - SID (Security Identifier) of the job user
1018
* BOOL - true if removing succeeded, false if it failed
1021
*******************************************************************************/
1022
static BOOL RemoveAceFromDesktop(HDESK hDesk, PSID pSid)
1024
SECURITY_DESCRIPTOR *pSD = NULL;
1026
BOOL bDaclPresent = TRUE;
1027
BOOL bDaclDefaulted = FALSE;
1029
DWORD SDLengthNeeded = 0;
1032
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
1037
if(WaitForSingleObject(g_hDeskACLMutex, INFINITE) == WAIT_OBJECT_0) {
1040
// Obtain DACL from Windows station, search for ACE, remove ACE from DACL
1041
bSecRet = GetUserObjectSecurity(hDesk, &si, pSD, SDLength, &SDLengthNeeded);
1043
pSD = (SECURITY_DESCRIPTOR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SDLengthNeeded);
1045
bSecRet = GetUserObjectSecurity(hDesk, &si, pSD, SDLengthNeeded, &SDLengthNeeded);
1046
bSecRet = GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDeskDacl, &bDaclDefaulted);
1048
for(DWORD i=0; i<pDeskDacl->AceCount; i++) {
1049
bSecRet = GetAce(pDeskDacl, i, &pDeskAce);
1050
if(((ACCESS_ALLOWED_ACE*)pDeskAce)->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
1051
pListSid = (PSID)&(((ACCESS_ALLOWED_ACE*)pDeskAce)->SidStart);
1053
bSecRet = IsValidSid(pSid);
1054
bSecRet = IsValidSid(pListSid);
1055
DWORD dwSidLength = GetLengthSid(pSid);
1056
DWORD dwListSidLength = GetLengthSid(pListSid);
1058
for(DWORD j=0; j<dwSidLength && j<dwListSidLength; j++) {
1059
if(*((BYTE*)pListSid+j) != *((BYTE*)pSid+j)) {
1065
DeleteAce(pDeskDacl, i);
1070
SetUserObjectSecurity(hDesk, &si, pSD);
1075
HeapFree(GetProcessHeap(), 0, (LPVOID)pSD);
1078
ReleaseMutex(g_hDeskACLMutex);
1083
/****** GetJobStartModeFromConf() *********************************************
1085
* GetJobStartModeFromConf() -- searches conf for display_win_gui and
1086
* retrieves the corresponding value.
1089
* static BOOL GetJobStartModeFromConf(char **conf, int nconf)
1092
* Searchs conf for the complex variable display_win_gui and retrieves
1096
* char **conf - the configuration that is to be searched
1097
* int nconf - number of entries in configuration
1100
* BOOL - TRUE if the value of the complex variable display_win_gui is "1",
1104
*******************************************************************************/
1105
static BOOL GetJobStartModeFromConf(char **conf, int nconf)
1111
BOOL bFound = FALSE;
1113
for(i=0; i<nconf && bFound==FALSE; i++) {
1114
tmp = strdup(conf[i]);
1115
ptr = strtok(tmp, "=");
1116
if(ptr && stricmp(ptr, "display_win_gui")==0) {
1117
ptr=strtok(NULL, "=");
1118
if(ptr && stricmp(ptr, "1")==0) {
1128
/****** GetModeFromEnv() ******************************************************
1130
* GetModeFromEnv() -- searches env for given variable and retrieves
1131
* the corresponding value.
1134
* static BOOL GetModeFromEnv(const char *mode, char **env, int nenv)
1137
* Searchs env for the given variable and retrieves it's value.
1141
* char **env - the environment that is to be searched
1142
* int nenv - number of entries in environment
1145
* BOOL - TRUE if the value of the environment variable is "1"
1146
* or "TRUE" (not case sensitive), else FALSE.
1149
*******************************************************************************/
1150
static BOOL GetModeFromEnv(const char *mode, char **env, int nenv)
1156
BOOL bFound = FALSE;
1158
for(i=0; i<nenv && bFound==FALSE; i++) {
1159
tmp = strdup(env[i]);
1160
ptr = strtok(tmp, "=");
1161
if(ptr && stricmp(ptr, mode)==0) {
1162
ptr=strtok(NULL, "=");
1163
if(ptr && (stricmp(ptr, "TRUE")==0 || stricmp(ptr, "1")==0)) {
1173
/****** RedirectStdHandles() **************************************************
1175
* RedirectStdHandles() -- Redirects stdout and stderr
1178
* static DWORD RedirectStdHandles(const C_Job &Job,
1179
* HANDLE &hStdout, HANDLE &hStderr)
1182
* Redirects stdout and stderr of the job to files. The file names are
1183
* retrieved from the job's environment.
1186
* C_Job &Job - The job object of the job for whom the standard handles
1187
* are to be redirected.
1190
* HANDLE &hStdout - The redirected stdout handle
1191
* HANDLE &hStderr - The redirected stderr handle
1195
* 1: Can't create stdout file
1196
* 2: Can't create stderr file
1199
*******************************************************************************/
1200
static DWORD RedirectStdHandles(const C_Job &Job, HANDLE &hStdout, HANDLE &hStderr)
1202
const char *pszStdout, *pszStderr, *pszMerge;
1207
pszStdout = Job.GetConfValue("stdout_path");
1208
pszStderr = Job.GetConfValue("stderr_path");
1209
pszMerge = Job.GetConfValue("merge_stderr");
1210
if(pszMerge != NULL) {
1211
sscanf(pszMerge, "%d", &iMerge);
1214
hStdout = CreateFile(
1217
FILE_SHARE_READ|FILE_SHARE_WRITE,
1220
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
1222
if(hStdout == INVALID_HANDLE_VALUE) {
1225
SetFilePointer(hStdout, 1, NULL, FILE_END);
1226
SetHandleInformation(hStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
1229
hStderr = CreateFile(
1232
FILE_SHARE_READ|FILE_SHARE_WRITE,
1235
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
1238
DuplicateHandle(GetCurrentProcess(), hStdout,
1239
GetCurrentProcess(), &hStderr,
1240
0, TRUE, DUPLICATE_SAME_ACCESS);
1242
if(hStderr == INVALID_HANDLE_VALUE) {
1245
SetFilePointer(hStderr, 1, NULL, FILE_END);
1246
SetHandleInformation(hStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
1248
catch(int ret_val) {
1254
/******************************************************************************
1255
* Test/Debugging functions
1256
******************************************************************************/
1257
static void WriteEnvToFile(char *pszEnv, char *pszFile)
1262
fp = fopen(pszFile, "w+");
1264
while(*ptr != '\0' || *(ptr+1) != '\0') {
1266
fwrite("\n", 1, 1, fp);
1268
fwrite(ptr, 1, 1, fp);
1279
// Copy current Job object to pipe
1280
HANDLE hReadParent, hWriteChild;
1281
HANDLE hWriteParent, hReadChild;
1282
HANDLE hDuplReadParent, hDuplWriteParent;
1283
SECURITY_ATTRIBUTES secAttr;
1285
ZeroMemory(&secAttr, sizeof(secAttr));
1286
secAttr.nLength = sizeof(secAttr);
1287
secAttr.bInheritHandle = TRUE;
1289
// Create inheritable pipe
1290
if(!CreatePipe(&hReadParent, &hWriteChild, &secAttr, 10000)) {
1293
// Create non-inheritable handle of one side of pipe
1294
DuplicateHandle(GetCurrentProcess(),
1296
GetCurrentProcess(),
1298
DUPLICATE_SAME_ACCESS,
1300
DUPLICATE_SAME_ACCESS);
1301
// Close inheritable duplicate of handle of one side of pipe
1302
CloseHandle(hReadParent);
1304
// Create inheritable pipe
1305
if(!CreatePipe(&hReadChild, &hWriteParent, &secAttr, 10000)) {
1308
// Create non-inheritable handle of one side of pipe
1309
DuplicateHandle(GetCurrentProcess(),
1311
GetCurrentProcess(),
1313
DUPLICATE_SAME_ACCESS,
1315
DUPLICATE_SAME_ACCESS);
1316
// Close inheritable duplicate of handle of one side of pipe
1317
CloseHandle(hWriteParent);
1327
// First wait for data on the pipe
1328
WriteToLogFile("Now reading data from the pipe.");
1329
iRet = Job.Unserialize(hDuplReadParent);
1330
WriteToLogFile("Read data from the pipe: %d.", iRet);
1332
FlushFileBuffers(hDuplWriteParent);
1333
bRet = CloseHandle(hDuplWriteParent);
1334
WriteToLogFile("CloseHandle(hDuplWriteParent) returned %d", bRet);
1336
bRet = CloseHandle(hDuplReadParent);
1337
WriteToLogFile("CloseHandle(hDuplReadParent) returned %d.", bRet);