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 + -
显示快捷键?