--- httpd-2.2.17_orig/modules/generators/fcgid_conf.c 2010-11-04 11:43:30.000000000 -0700 +++ httpd-2.2.17_orig/modules/generators/fcgid_conf.c 2011-04-04 19:57:13.000000000 -0700 @@ -60,6 +60,7 @@ #define DEFAULT_WRAPPER_KEY "ALL" #define WRAPPER_FLAG_VIRTUAL "virtual" +#define DEFAULT_IMPERSONATION_FLAG_OFF 0 void *create_fcgid_server_config(apr_pool_t * p, server_rec * s) { fcgid_server_conf *config = apr_pcalloc(p, sizeof(*config)); @@ -85,6 +86,13 @@ config->termination_score = DEFAULT_TERMINATION_SCORE; config->time_score = DEFAULT_TIME_SCORE; config->zombie_scan_interval = DEFAULT_ZOMBIE_SCAN_INTERVAL; + + config->bImpersonation = DEFAULT_IMPERSONATION_FLAG_OFF; + config->pszImpersonationCredentialProviderPath = NULL; + +#ifdef WIN32 + config->hJobObjectForAutoCleanup = NULL; +#endif /*WIN32*/ } /* Redundant; pcalloc creates this structure; * config->default_init_env = NULL; @@ -749,6 +757,54 @@ return NULL; } +/* FcgidImpersonation + * + * On -> Impersonation is set to On, + * Requires FcgidImpersonationCredentialProvider + * Off -> Default setting. Impersonation is set to off. + * + */ +const char *set_impersonation(cmd_parms * cmd, + void *dummy, int arg) +{ + server_rec *s = cmd->server; + fcgid_server_conf *config = + ap_get_module_config(s->module_config, &fcgid_module); + + config->bImpersonation = arg; + ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, + "INFO: Fcgid Impersonation flag: %d ", + arg); + + return NULL; +} + +/* FcgidImpersonationCredentialProvider + * + * -> DLL path that provides Username and password for + * impersonation. Can be absolute or relative path. + * -> Function name that provides Username and password. + * + */ +const char *set_impersonation_provider_info(cmd_parms * cmd, void *dummmy, + const char *arg1, const char *arg2) +{ + server_rec *s = cmd->server; + fcgid_server_conf *config = + ap_get_module_config(s->module_config, &fcgid_module); + + if ((strlen(arg1)) > 0 && (strlen(arg2) > 0)){ + + config->pszImpersonationCredentialProviderPath = ap_server_root_relative(s->process->pool, arg1); + config->pszImpersonatorFunctionName = apr_pstrdup(s->process->pool, arg2); + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, + "mod_fcgid: ImpersonationHelper module %s, %s()", config->pszImpersonationCredentialProviderPath, arg2); + + return NULL; +} + fcgid_cmd_conf *get_access_info(request_rec * r, int *authoritative) { fcgid_dir_conf *config = --- httpd-2.2.17_orig/modules/generators/fcgid_conf.h 2010-11-04 12:14:16.000000000 -0700 +++ httpd-2.2.17_orig/modules/generators/fcgid_conf.h 2011-04-03 22:52:40.609375000 -0700 @@ -71,6 +71,10 @@ int termination_score; int time_score; int zombie_scan_interval; + /* FcgiImpersonation* - CGI process impersonation */ + BOOL bImpersonation; + char *pszImpersonationCredentialProviderPath; + char *pszImpersonatorFunctionName; /* global or vhost * scalar values have corresponding _set field to aid merging */ --- httpd-2.2.17_orig/modules/generators/fcgid_pm.h 2010-10-29 20:35:36.000000000 -0700 +++ httpd-2.2.17_orig/modules/generators/fcgid_pm.h 2011-04-03 22:53:20.484375000 -0700 @@ -57,4 +57,28 @@ apr_status_t procmgr_stop_procmgr(void *dummy); int procmgr_must_exit(void); +/* For Win32 process impersonation */ +#ifdef _WIN32 + +/* Holds the Custom DLL handle that is responsible for providing Username + * and password details to mod_fcgid.so + */ +extern HMODULE g_hImpersonationCredentialProviderDLL; + +/* Function signature that Impersonation Helper module/DLL should export in + * order to provide Username and password details for security token + * impersonation + */ +typedef apr_uint32_t (FAR WINAPI *PFNGETUSERCREDENTIALS)( + IN OUT apr_byte_t* pUtf8UserNameBuffer, + IN OUT apr_uint32_t* pdwUserNameBufferLen, + IN OUT apr_byte_t* pUtf8PasswordBuffer, + IN OUT apr_uint32_t* pdwPasswordBufferLen); + +/* Function pointer to export present in Custom DLL which provides Username + * and password + */ +extern PFNGETUSERCREDENTIALS g_pfnGetUserCredentials; +#endif /*_WIN32*/ + #endif --- httpd-2.2.17_orig/modules/generators/fcgid_pm_win.c 2010-10-29 20:35:36.000000000 -0700 +++ httpd-2.2.17_orig/modules/generators/fcgid_pm_win.c 2011-04-03 22:55:54.937500000 -0700 @@ -32,6 +32,10 @@ static int g_must_exit = 0; static int g_wakeup_timeout = 0; +/* For cgi process impersonation */ +HMODULE g_hImpersonationCredentialProviderDLL = NULL; +PFNGETUSERCREDENTIALS g_pfnGetUserCredentials = NULL; + static void *APR_THREAD_FUNC wakeup_thread(apr_thread_t * thd, void *data) { while (!g_must_exit) { @@ -124,6 +128,32 @@ exit(1); } + + /* Initialize ImpersonationHelper module refereces*/ + if (sconf->bImpersonation == TRUE && + g_hImpersonationCredentialProviderDLL == NULL){ + + g_hImpersonationCredentialProviderDLL = LoadLibrary(sconf->pszImpersonationCredentialProviderPath); + + if (g_hImpersonationCredentialProviderDLL == NULL){ + rv = apr_get_os_error(); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_server, + "mod_fcgid: can't load ImpersonationCredentialProviderDLL %s", sconf->pszImpersonationCredentialProviderPath); + return rv; + } + + g_pfnGetUserCredentials + = (PFNGETUSERCREDENTIALS) GetProcAddress( + g_hImpersonationCredentialProviderDLL, + sconf->pszImpersonatorFunctionName); + if (g_pfnGetUserCredentials == NULL){ + rv = apr_get_os_error(); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_server, + "mod_fcgid: can't load ImpersonationCredentialProviderDLL function %s", sconf->pszImpersonatorFunctionName); + return rv; + } + } + return APR_SUCCESS; } @@ -279,6 +309,14 @@ } } + /* Release the impersonation's credential provider helper DLL */ + if (g_hImpersonationCredentialProviderDLL != NULL) { + FreeLibrary(g_hImpersonationCredentialProviderDLL); + + g_hImpersonationCredentialProviderDLL = NULL; + g_pfnGetUserCredentials = NULL; + } + if (g_wakeup_thread) return apr_thread_join(&status, g_wakeup_thread); --- httpd-2.2.17_orig/modules/generators/fcgid_proc_win.c 2010-04-29 15:26:08.000000000 -0700 +++ httpd-2.2.17_orig/modules/generators/fcgid_proc_win.c 2011-04-03 23:08:17.468750000 -0700 @@ -50,6 +50,8 @@ static int g_process_counter = 0; +extern PFNGETUSERCREDENTIALS g_pfnGetUserCredentials; + static apr_status_t close_finish_event(void *finishevent) { HANDLE *finish_event = finishevent; @@ -58,6 +60,101 @@ return APR_SUCCESS; } +/* CGI process impersonation routine + */ +apr_status_t proc_impersonate(fcgid_proc_info *procinfo, apr_procattr_t *proc_attr) +{ +#define BUFFERLEN 1024 + char szUsername[BUFFERLEN] = {0}; + char szPassword[BUFFERLEN] = {0}; + int nUsernameLen = BUFFERLEN; + int nPasswordLen = BUFFERLEN; + + apr_status_t rv = APR_BADARG; + apr_uint32_t dwError = 0; + apr_uint32_t dwTimer = GetTickCount(); + + fcgid_server_conf *sconf = ap_get_module_config(procinfo->main_server-> + module_config, &fcgid_module); + + if (sconf == NULL){ + ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, + "mod_fcgid: fcgi server configuration info unavailable"); + return rv; + } + + if (sconf->bImpersonation == FALSE){ + return APR_SUCCESS; + } + + ap_log_error(APLOG_MARK, /*APLOG_DEBUG*/APLOG_INFO, 0, procinfo->main_server, + "mod_fcgid: Starting Impersonation started"); + + if (proc_attr == NULL){ + ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, + "mod_fcgid: process attribute info unavailable"); + return rv; + } + + if (g_hImpersonationCredentialProviderDLL == NULL){ + rv = APR_FROM_OS_ERROR(ERROR_DLL_NOT_FOUND); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, + "mod_fcgid: Credential provider module unavailable"); + return rv; + } + + if (g_pfnGetUserCredentials == NULL){ + rv = APR_FROM_OS_ERROR(ERROR_BAD_DLL_ENTRYPOINT); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, + "mod_fcgid: Credential provider module entry point unavailable"); + return rv; + } + + + /* Get credentials, note that we expect credential caching to be done by + * the provider DLL for security reasons + */ + dwError = g_pfnGetUserCredentials(szUsername, &nUsernameLen, + szPassword, &nPasswordLen); + if (dwError != ERROR_SUCCESS){ + rv = APR_FROM_OS_ERROR(dwError); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, + "mod_fcgid: error retreiving credientials from " + "ImpersonationCredentialProviderDLL %s function %s", + sconf->pszImpersonationCredentialProviderPath, + sconf->pszImpersonatorFunctionName); + return rv; + } + szUsername[nUsernameLen] = 0; + szPassword[nPasswordLen] = 0; + + + /* In order for CGI process to access remote DB in Win Authentication + * mode we raise the impersonation to Delegation level + */ + apr_procattr_impersonation_level_set(proc_attr, SecurityDelegation); + + /* Request imperonsation with delegation rights + */ + rv = apr_procattr_user_set(proc_attr, szUsername, szPassword); + if (rv != APR_SUCCESS){ + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server, + "mod_fcgid: Impersonation failed for user: %s password: %s", + szUsername, "*******" /*szPassword*/); + return rv; + } + + /* Wipe out the username and password details from memory to avoid exposing + * the same from VM images, crash dumps, etc. + */ + SecureZeroMemory(szUsername, sizeof(szUsername)); + SecureZeroMemory(szPassword, sizeof(szPassword)); + + ap_log_error(APLOG_MARK, /*APLOG_DEBUG*/ APLOG_INFO, 0, procinfo->main_server, + "mod_fcgid: Impersonation took %u ms", GetTickCount() - dwTimer); + + return rv; +} apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, fcgid_procnode *procnode) { @@ -166,6 +263,10 @@ return APR_ENOPROC; } + + /* LTAC - FcgidImpersonation feature*/ + rv = proc_impersonate(procinfo, proc_attr); + /* fork and exec now */ rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv, proc_environ, proc_attr, procnode->proc_pool); --- httpd-2.2.17_orig/modules/generators/mod_fcgid.c 2010-10-28 23:53:30.000000000 -0700 +++ httpd-2.2.17_orig/modules/generators/mod_fcgid.c 2011-04-03 23:11:26.468750000 -0700 @@ -802,6 +802,11 @@ return APR_SUCCESS; } +const char *set_impersonation(cmd_parms * cmd, + void *config, int arg); +const char *set_impersonation_provider_info(cmd_parms * cmd, void *dummmy, + const char *name, const char *value); + static const command_rec fcgid_cmds[] = { AP_INIT_TAKE1("FcgidAccessChecker", set_access_info, NULL, ACCESS_CONF | OR_FILEINFO, @@ -895,6 +900,12 @@ AP_INIT_TAKE1("FcgidZombieScanInterval", set_zombie_scan_interval, NULL, RSRC_CONF, "scan interval for zombie process"), + AP_INIT_FLAG("FcgidImpersonation", set_impersonation, NULL, RSRC_CONF, + "Set to on if CGI process should be impersonated as another user"), + /* Currently we support only Windows DLLs as Credential provider */ + AP_INIT_TAKE12("FcgidImpersonationCredentialProvider", + set_impersonation_provider_info, NULL, RSRC_CONF, + "Module path and function name that provides DB user credentials for CGI process impersonation"), /* The following directives are all deprecated in favor * of a consistent use of the Fcgid prefix. --- httpd-2.2.17_orig/srclib/apr/include/apr_thread_proc.h 2010-01-06 04:36:50.000000000 -0800 +++ httpd-2.2.17_orig/srclib/apr/include/apr_thread_proc.h 2011-04-03 22:10:20.968750000 -0700 @@ -568,6 +568,19 @@ const char *username, const char *password); + +#if defined(_WIN32) || defined(DOXYGEN) +/** + * Set the running process security impersonation/delegation level + * @param attr The procattr we care about + * @param si The security impersonation level the current process + * should get. + */ +APR_DECLARE(apr_status_t) +apr_procattr_impersonation_level_set(apr_procattr_t *attr, + SECURITY_IMPERSONATION_LEVEL si); +#endif /*_WIN32*/ + /** * Set the group used for running process * @param attr The procattr we care about. --- httpd-2.2.17_orig/srclib/apr/include/arch/win32/apr_arch_threadproc.h 2007-08-26 16:19:56.000000000 -0700 +++ httpd-2.2.17_orig/srclib/apr/include/arch/win32/apr_arch_threadproc.h 2011-04-03 22:09:34.750000000 -0700 @@ -61,6 +61,13 @@ HANDLE user_token; LPSECURITY_ATTRIBUTES sa; LPVOID sd; + +/* LTAC: Contains impersonation level required for impersonating current process + */ + struct _apr_impersonation { + apr_byte_t bIsSet; + SECURITY_IMPERSONATION_LEVEL si; + } impersonationLevel; #endif }; --- httpd-2.2.17_orig/srclib/apr/threadproc/win32/proc.c 2008-04-17 12:57:22.000000000 -0700 +++ httpd-2.2.17_orig/srclib/apr/threadproc/win32/proc.c 2011-04-04 20:35:47.765625000 -0700 @@ -237,6 +237,20 @@ } #endif +APR_DECLARE(apr_status_t) +apr_procattr_impersonation_level_set(apr_procattr_t *attr, + SECURITY_IMPERSONATION_LEVEL si) +{ + if (attr == NULL){ + return APR_BADARG; + } + + attr->impersonationLevel.bIsSet = TRUE; + attr->impersonationLevel.si = si; + + return APR_SUCCESS; +} + APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, const char *username, const char *password) @@ -290,10 +304,21 @@ return rv; } } + /* LTAC: For apr_procattr_user_set() API backward compatibility. + * Modules called apr_procattr_user_set() assuming impersonation level + * is set to 'SecurityImpersonation'. Therefore we still maintain this + * assumption if Impersonation level is not set explicitly by the new + * apr_procattr_impersonation_level_set() API. + */ + if (!attr->impersonationLevel.bIsSet) + { + apr_procattr_impersonation_level_set(attr, SecurityImpersonation); + } if (!LogonUserW(wusername, NULL, wpassword ? wpassword : L"", - LOGON32_LOGON_NETWORK, + attr->impersonationLevel.si == SecurityDelegation ? + LOGON32_LOGON_NETWORK_CLEARTEXT :LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &user)) { /* Logon Failed */ @@ -305,7 +330,7 @@ if (!DuplicateTokenEx(user, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, - SecurityImpersonation, + attr->impersonationLevel.si, TokenPrimary, &(attr->user_token))) { /* Failed to duplicate the user token */ @@ -321,7 +346,8 @@ attr->sa = apr_palloc(attr->pool, sizeof(SECURITY_ATTRIBUTES)); attr->sa->nLength = sizeof (SECURITY_ATTRIBUTES); attr->sa->lpSecurityDescriptor = attr->sd; - attr->sa->bInheritHandle = FALSE; + attr->sa->bInheritHandle = + (attr->impersonationLevel.si == SecurityDelegation) ? TRUE : FALSE; /* register the cleanup */ apr_pool_cleanup_register(attr->pool, (void *)attr,