From c806dca62cc881759aeb0c7c1d5a92a3326fed06 Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Mon, 18 Mar 2002 04:48:34 +0000 Subject: [PATCH] add security impersonation feature for running under IIS security --- sapi/cgi/cgi_main.c | 18 ++++ sapi/cgi/libfcgi/include/fcgios.h | 4 + sapi/cgi/libfcgi/os_win32.c | 158 ++++++++++++++++++++++++++++-- 3 files changed, 171 insertions(+), 9 deletions(-) diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index d45037150e..a94b26669d 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -81,6 +81,9 @@ #ifdef PHP_FASTCGI #include "fcgi_config.h" #include "fcgiapp.h" +/* don't want to include fcgios.h, causes conflicts */ +extern int OS_SetImpersonate(void); + FCGX_Stream *in, *out, *err; FCGX_ParamArray envp; @@ -475,6 +478,9 @@ int main(int argc, char *argv[]) int max_requests = 500; int requests = 0; int fastcgi = !FCGX_IsCGI(); +#ifdef PHP_WIN32 + int impersonate = 0; +#endif if (fastcgi) { /* Calculate environment size */ @@ -729,6 +735,18 @@ If you are running IIS, you may safely set cgi.force_redirect=0 in php.ini.\n\ #ifdef PHP_FASTCGI /* start of FAST CGI loop */ + +#ifdef PHP_WIN32 + /* attempt to set security impersonation for fastcgi + will only happen on NT based OS, others will ignore it. */ + if (fastcgi) { + if (cfg_get_long("fastcgi.impersonate", &impersonate) == FAILURE) { + impersonate = 0; + } + if (impersonate) OS_SetImpersonate(); + } +#endif + while (!fastcgi || FCGX_Accept( &in, &out, &err, &cgi_env ) >= 0) { diff --git a/sapi/cgi/libfcgi/include/fcgios.h b/sapi/cgi/libfcgi/include/fcgios.h index bc62a185d5..4abc0dac04 100644 --- a/sapi/cgi/libfcgi/include/fcgios.h +++ b/sapi/cgi/libfcgi/include/fcgios.h @@ -125,6 +125,10 @@ DLLAPI void OS_SetFlags(int fd, int flags); DLLAPI void OS_ShutdownPending(void); +#ifdef _WIN32 +DLLAPI int OS_SetImpersonate(void); +#endif + #if defined (__cplusplus) || defined (c_plusplus) } /* terminate extern "C" { */ #endif diff --git a/sapi/cgi/libfcgi/os_win32.c b/sapi/cgi/libfcgi/os_win32.c index f002e7d851..2415e03bb1 100644 --- a/sapi/cgi/libfcgi/os_win32.c +++ b/sapi/cgi/libfcgi/os_win32.c @@ -55,6 +55,7 @@ static HANDLE acceptMutex = INVALID_HANDLE_VALUE; static BOOLEAN shutdownPending = FALSE; static BOOLEAN shutdownNow = FALSE; +static BOOLEAN bImpersonate = FALSE; /* * An enumeration of the file types * supported by the FD_TABLE structure. @@ -290,6 +291,17 @@ static DWORD WINAPI ShutdownRequestThread(LPVOID arg) } } +int OS_SetImpersonate(void) +{ + char *os_name = NULL; + os_name = getenv("OS"); + if (stricmp(os_name, "Windows_NT") == 0) { + bImpersonate = TRUE; + return 1; + } + return 0; +} + /* *-------------------------------------------------------------- * @@ -319,7 +331,7 @@ int OS_LibInit(int stdioFds[3]) return 0; InitializeCriticalSection(&fdTableCritical); - + /* * Initialize windows sockets library. */ @@ -589,6 +601,7 @@ void OS_LibShutdown() if (stdioHandles[0] != INVALID_HANDLE_VALUE) { DisconnectNamedPipe(hListen); CancelIo(hListen); + if (bImpersonate) RevertToSelf(); } DeleteCriticalSection(&fdTableCritical); @@ -673,6 +686,83 @@ static short getPort(const char * bindPath) return port; } +/** +This function builds a Dacl which grants the creator of the objects +FILE_ALL_ACCESS and Everyone FILE_GENERIC_READ and FILE_GENERIC_WRITE +access to the object. + +This Dacl allows for higher security than a NULL Dacl, which is common for +named-pipes, as this only grants the creator/owner write access to the +security descriptor, and grants Everyone the ability to "use" the named-pipe. +This scenario prevents a malevolent user from disrupting service by preventing +arbitrary access manipulation. +**/ +BOOL +BuildNamedPipeAcl( + PACL pAcl, + PDWORD cbAclSize + ) +{ + DWORD dwAclSize; + + SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY siaCreator = SECURITY_CREATOR_SID_AUTHORITY; + + BYTE BufEveryoneSid[32]; + BYTE BufOwnerSid[32]; + + PSID pEveryoneSid = (PSID)BufEveryoneSid; + PSID pOwnerSid = (PSID)BufOwnerSid; + + // + // compute size of acl + // + dwAclSize = sizeof(ACL) + + 2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) + + GetSidLengthRequired( 1 ) + // well-known Everyone Sid + GetSidLengthRequired( 1 ) ; // well-known Creator Owner Sid + + if(*cbAclSize < dwAclSize) { + *cbAclSize = dwAclSize; + return FALSE; + } + + *cbAclSize = dwAclSize; + + // + // intialize well known sids + // + + if(!InitializeSid(pEveryoneSid, &siaWorld, 1)) return FALSE; + *GetSidSubAuthority(pEveryoneSid, 0) = SECURITY_WORLD_RID; + + if(!InitializeSid(pOwnerSid, &siaCreator, 1)) return FALSE; + *GetSidSubAuthority(pOwnerSid, 0) = SECURITY_CREATOR_OWNER_RID; + + if(!InitializeAcl(pAcl, dwAclSize, ACL_REVISION)) + return FALSE; + + // + // + if(!AddAccessAllowedAce( + pAcl, + ACL_REVISION, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + pEveryoneSid + )) + return FALSE; + + // + // + return AddAccessAllowedAce( + pAcl, + ACL_REVISION, + FILE_ALL_ACCESS, + pOwnerSid + ); +} + + /* * OS_CreateLocalIpcFd -- * @@ -774,7 +864,13 @@ int OS_CreateLocalIpcFd(const char *bindPath, int backlog, int bCreateMutex) } else { - HANDLE hListenPipe = INVALID_HANDLE_VALUE; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + BYTE AclBuf[ 64 ]; + DWORD cbAclSize = 64; + PACL pAcl = (PACL)AclBuf; + + HANDLE hListenPipe = INVALID_HANDLE_VALUE; char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); if (! pipePath) @@ -786,11 +882,42 @@ int OS_CreateLocalIpcFd(const char *bindPath, int backlog, int bCreateMutex) strcpy(pipePath, bindPathPrefix); strcat(pipePath, bindPath); + if (bImpersonate) { + // get the security attributes for Everybody to connect + // we do this so that multithreaded servers that run + // threads under secured users can access pipes created + // by a system level thread (for instance, IIS) + // + // suppress errors regarding startup directory, etc + // + SetErrorMode(SEM_FAILCRITICALERRORS); + + if(!BuildNamedPipeAcl(pAcl, &cbAclSize)) { + fprintf(stderr, "BuildNamedPipeAcl"); + return -100; + } + + if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { + fprintf(stderr, "InitializeSecurityDescriptor"); + return -100; + } + + if(!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { + fprintf(stderr, "SetSecurityDescriptorDacl"); + return -100; + } + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = &sd; // default Dacl of caller + sa.bInheritHandle = TRUE; + + } + hListenPipe = CreateNamedPipe(pipePath, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE, PIPE_UNLIMITED_INSTANCES, - 4096, 4096, 0, NULL); + 4096, 4096, 0, bImpersonate?&sa:NULL); free(pipePath); @@ -841,7 +968,7 @@ int OS_FcgiConnect(char *bindPath) { short port = getPort(bindPath); int pseudoFd = -1; - + unsigned int flags = FILE_FLAG_OVERLAPPED; if (port) { struct hostent *hp; @@ -916,12 +1043,16 @@ int OS_FcgiConnect(char *bindPath) strcpy(pipePath, bindPathPrefix); strcat(pipePath, bindPath); + if (bImpersonate) { + flags |= SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION; + } + hPipe = CreateFile(pipePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, + flags, NULL); free(pipePath); @@ -1659,11 +1790,19 @@ static int acceptNamedPipe() } } - ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1); - if (ipcFd == -1) - { + // + // impersonate the client + // + if(bImpersonate && !ImpersonateNamedPipeClient(hListen)) { DisconnectNamedPipe(hListen); - } + } else { + ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1); + if (ipcFd == -1) + { + DisconnectNamedPipe(hListen); + if (bImpersonate) RevertToSelf(); + } + } return ipcFd; } @@ -1856,6 +1995,7 @@ int OS_IpcClose(int ipcFd) return -1; if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) { OS_Close(ipcFd); + if (bImpersonate) RevertToSelf(); return 0; } else { return -1; -- 2.40.0