erlsrv_service.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 952 行 · 第 1/2 页
C
952 行
#include <windows.h>#include <winsvc.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "erlsrv_global.h"#include "erlsrv_registry.h"#include "erlsrv_util.h"#include "erlsrv_service.h"static HANDLE eventStop;static HANDLE eventKillErlang; static CRITICAL_SECTION crit;static SERVICE_STATUS_HANDLE statusHandle;static DWORD currentState;static void fill_status(SERVICE_STATUS *status){ status->dwServiceType = SERVICE_WIN32_OWN_PROCESS; status->dwCurrentState = 0; status->dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; status->dwWin32ExitCode = NO_ERROR; status->dwServiceSpecificExitCode = 0; status->dwCheckPoint = 0; status->dwWaitHint = 0;}static BOOL set_start_pending(int waithint, int checkpoint){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_START_PENDING; LeaveCriticalSection(&crit); stat.dwControlsAccepted = 0; stat.dwCheckPoint = checkpoint; stat.dwWaitHint = waithint; return SetServiceStatus(statusHandle, &stat);}static BOOL set_stop_pending(int waithint, int checkpoint){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_STOP_PENDING; LeaveCriticalSection(&crit); stat.dwControlsAccepted = 0; stat.dwCheckPoint = checkpoint; stat.dwWaitHint = waithint; return SetServiceStatus(statusHandle, &stat);}static BOOL set_running(){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_RUNNING; LeaveCriticalSection(&crit); return SetServiceStatus(statusHandle, &stat);}static BOOL set_stopped(int error){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_STOPPED; LeaveCriticalSection(&crit); stat.dwWin32ExitCode = error; return SetServiceStatus(statusHandle, &stat);} static BOOL reset_current(){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); stat.dwCurrentState = currentState; LeaveCriticalSection(&crit); return SetServiceStatus(statusHandle, &stat);}static VOID WINAPI handler(DWORD control){ char buffer[1024]; sprintf(buffer,"handler called with control = %d.",(int) control); log_debug(buffer); switch(control){ case SERVICE_CONTROL_STOP: set_stop_pending(30000,1); SetEvent(eventStop); return; case SERVICE_CONTROL_SHUTDOWN: return; default: reset_current(); break; } return;}typedef struct _server_info { RegEntry *keys; PROCESS_INFORMATION info; HANDLE erl_stdin; char *event_name;} ServerInfo;typedef struct { BOOL initialized; TOKEN_DEFAULT_DACL *defdacl; PACL newacl; PSID adminsid;} SaveAclStruct;static BOOL reset_acl(SaveAclStruct *save_acl){ HANDLE tokenh; if(!save_acl->initialized) return FALSE; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ|TOKEN_WRITE,&tokenh)){ log_warning("Failed to open access token."); return FALSE; } save_acl->initialized = FALSE; if(!SetTokenInformation(tokenh, TokenDefaultDacl, save_acl->defdacl, sizeof(TOKEN_DEFAULT_DACL))){ log_warning("Failed to get default ACL from token."); CloseHandle(tokenh); LocalFree(save_acl->defdacl); LocalFree(save_acl->newacl); FreeSid(save_acl->adminsid); return FALSE; } CloseHandle(tokenh); LocalFree(save_acl->defdacl); LocalFree(save_acl->newacl); FreeSid(save_acl->adminsid); return TRUE;} static BOOL new_acl(SaveAclStruct *save_acl){ HANDLE tokenh; TOKEN_DEFAULT_DACL newdacl; DWORD required; PACL oldacl; PACL newacl; int i; ACL_SIZE_INFORMATION si; size_t newsize; PSID extra_sid; SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY; TOKEN_DEFAULT_DACL dummy; save_acl->initialized = FALSE; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ|TOKEN_WRITE,&tokenh)){ log_warning("Failed to open access token."); return FALSE; } save_acl->defdacl = &dummy; required = sizeof(TOKEN_DEFAULT_DACL); GetTokenInformation(tokenh, TokenDefaultDacl, &(save_acl->defdacl), sizeof(TOKEN_DEFAULT_DACL), &required); if(required == 0){ log_warning("Failed to get any ACL info from token."); CloseHandle(tokenh); return FALSE; } save_acl->defdacl = LocalAlloc(LPTR,required); if(!GetTokenInformation(tokenh, TokenDefaultDacl, save_acl->defdacl, required, &required)){#ifdef HARDDEBUG { char *mes; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &mes, 0, NULL ); log_info(mes); LocalFree(mes); }#endif log_warning("Failed to get default ACL from token."); CloseHandle(tokenh); return FALSE; } oldacl = save_acl->defdacl->DefaultDacl; if(!GetAclInformation(oldacl, &si, sizeof(si), AclSizeInformation)){ log_warning("Failed to get size information for ACL"); CloseHandle(tokenh); return FALSE; } if(!AllocateAndInitializeSid(&nt_auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &extra_sid)){ log_warning("Failed to initialize administrator SID."); CloseHandle(tokenh); return FALSE; } newsize = si.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(extra_sid); newacl = LocalAlloc(LPTR,newsize); if(!InitializeAcl(newacl, newsize, ACL_REVISION)){ log_warning("Failed to initialize new ACL."); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } for(i=0;i<((int)si.AceCount);++i){ ACE_HEADER *ace_header; if (!GetAce (oldacl, i, &ace_header)){ log_warning("Failed to get ACE from old ACL."); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } if(!AddAce(newacl,ACL_REVISION,0xffffffff,ace_header, ace_header->AceSize)){ log_warning("Failed to set ACE in new ACL."); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } } if(!AddAccessAllowedAce(newacl, ACL_REVISION2, PROCESS_ALL_ACCESS, extra_sid)){ log_warning("Failed to add system ACE to new ACL."); LocalFree(newacl); FreeSid(extra_sid); return FALSE; } newdacl.DefaultDacl = newacl; if(!SetTokenInformation(tokenh, TokenDefaultDacl, &newdacl, sizeof(newdacl))){ log_warning("Failed to set token information"); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } save_acl->initialized = TRUE; save_acl->newacl = newacl; save_acl->adminsid = extra_sid; CloseHandle(tokenh); return TRUE;}static char **find_arg(char **arg, char *str){ char *tmp; int len; str = strdup(str); if((tmp = strchr(str,'=')) == NULL) goto fail; tmp++; *tmp = '\0'; len = tmp - str; while(*arg != NULL){ if(!_strnicmp(*arg,str,len)){ free(str); return arg; } ++arg; }fail: free(str); return NULL;} static char **merge_environment(char *current, char *add){ char **c_arg = env_to_arg(envdup(current)); char **a_arg = env_to_arg(envdup(add)); char **new; char **tmp; int i,j; for(i=0;c_arg[i] != NULL;++i) ; for(j=0;a_arg[j] != NULL;++j) ; new = malloc(sizeof(char *)*(i + j + 3)); for(i = 0; c_arg[i] != NULL; ++i) new[i] = strdup(c_arg[i]); new[i] = NULL; for(j = 0; a_arg[j] != NULL; ++j){ if((tmp = find_arg(new,a_arg[j])) != NULL){ free(*tmp); *tmp = strdup(a_arg[j]); } else { new[i++] = strdup(a_arg[j]); new[i] = NULL; } } free(arg_to_env(c_arg)); free(arg_to_env(a_arg)); return new;}static char *get_next_debug_file(char *prefix){ char *buffer = malloc(strlen(prefix)+12); int i; for(i=1;i<100;++i){ sprintf(buffer,"%s.%d",prefix,i); if(GetFileAttributes(buffer) == 0xFFFFFFFF) return buffer; } return NULL;}static BOOL start_a_service(ServerInfo *srvi){ STARTUPINFO start; char execbuff[MAX_PATH*4]; /* FIXME: Can get overflow! */ char namebuff[MAX_PATH]; char errbuff[MAX_PATH*4]; /* hmmm.... */ HANDLE write_pipe = NULL, read_pipe = NULL; SECURITY_ATTRIBUTES pipe_security; SECURITY_ATTRIBUTES attr; HANDLE nul; SaveAclStruct save_acl; char *my_environ; BOOL console_allocated = FALSE; if(!(*(srvi->keys[Env].data.bytes))){ my_environ = NULL; } else { char *tmp; char **merged = merge_environment((tmp = GetEnvironmentStrings()), srvi->keys[Env].data.bytes); FreeEnvironmentStrings(tmp); my_environ = arg_to_env(merged); } if(!*(srvi->keys[Machine].data.bytes) || (!*(srvi->keys[SName].data.bytes) && !*(srvi->keys[Name].data.bytes))){ log_error("Not enough parameters for erlang service."); if(my_environ) free(my_environ); return FALSE; } if(*(srvi->keys[SName].data.bytes)) sprintf(namebuff,"-nohup -sname %s",srvi->keys[SName].data.bytes); else sprintf(namebuff,"-nohup -name %s",srvi->keys[Name].data.bytes); if(srvi->keys[DebugType].data.value == DEBUG_TYPE_CONSOLE) strcat(namebuff," -keep_window"); if (srvi->event_name != NULL) { sprintf(execbuff,"\"%s\" -service_event %s %s %s", srvi->keys[Machine].data.bytes, srvi->event_name, namebuff, srvi->keys[Args].data.bytes); } else { sprintf(execbuff,"\"%s\" %s %s", srvi->keys[Machine].data.bytes, namebuff, srvi->keys[Args].data.bytes); } memset (&start, 0, sizeof (start)); start.cb = sizeof (start); start.dwFlags = STARTF_USESHOWWINDOW; start.wShowWindow = SW_HIDE; /* Console debugging implies no working StopAction */ if(srvi->keys[DebugType].data.value == DEBUG_TYPE_CONSOLE) { COORD coord = {80,999}; if(console_allocated = AllocConsole()) SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coord); else log_warning("Unable to allocate debugging console!"); } else if(*(srvi->keys[StopAction].data.bytes) || srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG){ pipe_security.nLength = sizeof(pipe_security); pipe_security.lpSecurityDescriptor = NULL; pipe_security.bInheritHandle = TRUE; if(!CreatePipe(&read_pipe,&write_pipe,&pipe_security,0)){ log_error("Could not create pipe for erlang service."); if(my_environ) free(my_environ); return FALSE; } if(srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG){ char *filename; if(*(srvi->keys[WorkDir].data.bytes)){ filename = malloc(strlen(srvi->keys[WorkDir].data.bytes) + 1 + strlen(service_name)+strlen(".debug")+1); sprintf(filename,"%s\\%s.debug", srvi->keys[WorkDir].data.bytes, service_name); } else { filename = malloc(strlen(service_name)+strlen(".debug")+1); sprintf(filename,"%s.debug",service_name); } log_debug(filename); if(srvi->keys[DebugType].data.value == DEBUG_TYPE_NEW){ char *tmpfn = get_next_debug_file(filename); if(tmpfn){ free(filename); filename = tmpfn; } else { log_warning("Number of debug files exceeds system defined " "limit, reverting to DebugType: reuse. "); } } nul = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &pipe_security, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); free(filename); } else { /* Not debugging */ nul = CreateFile("NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &pipe_security, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } if(nul == NULL){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?