mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

service.c (9633B)


      1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
      2 
      3    Mixmaster may be redistributed and modified under certain conditions.
      4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
      5    ANY KIND, either express or implied. See the file COPYRIGHT for
      6    details.
      7 
      8    Win32 Service support
      9    $Id: service.c 934 2006-06-24 13:40:39Z rabbi $ */
     10 
     11 
     12 #include <windows.h>
     13 #include <stdio.h>
     14 #include <direct.h>
     15 #include <io.h>
     16 #include <fcntl.h>
     17 
     18 #include "mix3.h"
     19 
     20 #ifdef WIN32SERVICE
     21 
     22 #define SVCNAME        "Mixmaster"
     23 #define SVCDISPLAYNAME "Mixmaster Service"
     24 
     25 
     26 /* internal variables */
     27 static SERVICE_STATUS           ssStatus;
     28 static SERVICE_STATUS_HANDLE    sshStatusHandle;
     29 static BOOL                     not_service = FALSE;
     30 
     31 static HANDLE hThread = NULL;
     32 static HANDLE hMustTerminate = NULL;
     33 
     34 /* internal function prototypes */
     35 VOID WINAPI service_ctrl(DWORD ctrl_code);
     36 VOID WINAPI service_main(DWORD argc, LPSTR *argv);
     37 static DWORD service_run(void);
     38 static void service_stop();
     39 static int set_stdfiles();
     40 static int install_service();
     41 static int remove_service();
     42 static int run_notservice(int argc, char **argv);
     43 BOOL WINAPI console_ctrl_handler(DWORD ctrl_type);
     44 static char *GetLastErrorText();
     45 static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id);
     46 static void event_log(DWORD id, char *eventmsg);
     47 
     48 int mix_main(int argc, char *argv[]);
     49 
     50 
     51 int main(int argc, char *argv[])
     52 {
     53     SERVICE_TABLE_ENTRY dispatchTable[] = {
     54 	{SVCNAME, (LPSERVICE_MAIN_FUNCTION)service_main},
     55 	{NULL,    NULL} };
     56 
     57     if ((argc > 1) && ((argv[1][0] == '-') && (argv[1][1] == '-'))) {
     58 	if (!_stricmp("install-svc", argv[1]+2))
     59 	    return install_service();
     60 	else if (!_stricmp("remove-svc", argv[1]+2))
     61 	    return remove_service();
     62 	else if (_stricmp("run-svc", argv[1]+2) && !is_nt_service())
     63 	    return run_notservice(argc, argv);
     64     } else if (!is_nt_service()) {
     65 	return run_notservice(argc, argv);
     66     }
     67     printf("mix --install-svc   install the service\n");
     68     printf("mix --remove-svc    remove the service\n");
     69     printf("mix --run-svc       run as a service\n");
     70     printf("mix -h          view a summary of the command line options.\n");
     71 
     72     printf("\nStartServiceCtrlDispatcher being called.\n" );
     73     printf("This may take several seconds.  Please wait.\n" );
     74     if (!StartServiceCtrlDispatcher(dispatchTable)) {
     75 	printf("Service not started: StartServiceCtrlDispatcher failed.\n" );
     76 	event_log(1000, "Service not started: StartServiceCtrlDispatcher failed");
     77     }
     78     return 0;
     79 } /* main */
     80 
     81 
     82 VOID WINAPI service_main(DWORD argc, LPSTR *argv)
     83 {
     84     DWORD err = 0;
     85 
     86     if (!(sshStatusHandle = RegisterServiceCtrlHandler(SVCNAME, service_ctrl)))
     87 	return;
     88 
     89     ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
     90     ssStatus.dwServiceSpecificExitCode = 0;
     91     if (send_status(SERVICE_START_PENDING, NO_ERROR, 1000, 1020))
     92 	err = service_run();
     93 
     94     send_status(SERVICE_STOPPED, err, 0, err ? 1030 : 30);
     95 } /* service_main */
     96 
     97 
     98 VOID WINAPI service_ctrl(DWORD ctrl_code)
     99 {   /* Handle the requested control code. */
    100     if (ctrl_code == SERVICE_CONTROL_STOP || ctrl_code == SERVICE_CONTROL_SHUTDOWN)
    101 	service_stop();
    102     else
    103 	send_status(ssStatus.dwCurrentState, NO_ERROR, 0, 1040 + ctrl_code);
    104 } /* service_ctrl */
    105 
    106 
    107 static DWORD service_run(void)
    108 {
    109     char filename[_MAX_PATH+1];
    110     char home[_MAX_PATH+1], *p;
    111     char *svc_argv[2] = {filename, "-D"};
    112 
    113     if (!hMustTerminate)
    114 	hMustTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
    115     set_nt_exit_event(hMustTerminate);
    116     DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
    117 	    &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
    118 
    119     GetModuleFileName(NULL , filename, _MAX_PATH);
    120     strcpy(home, filename);
    121     if (p = strrchr(home, '\\')) {
    122 	*p = 0;
    123 	chdir(home);
    124     }
    125 
    126     if (!set_stdfiles()) {
    127 	event_log(1010, "stdin|stdout|stderr not created");
    128 	return ERROR_SERVICE_NOT_ACTIVE;
    129     }
    130 
    131     send_status(SERVICE_RUNNING, NO_ERROR, 0, 1060);
    132     event_log(10, "Mixmaster Service started");
    133 
    134     mix_main(2, svc_argv);
    135     return 0;
    136 } /* service_run */
    137 
    138 
    139 static void service_stop(void)
    140 {
    141     send_status(SERVICE_STOP_PENDING, NO_ERROR, 5000, 1070);
    142     if (hMustTerminate) {
    143 	SetEvent(hMustTerminate);
    144 	if (WaitForSingleObject(hThread, 4500) == WAIT_TIMEOUT) {
    145 	    if (hThread) {
    146 	        TerminateThread(hThread, 0);
    147 	        event_log(1080, "Mixmaster Service terminated forcibly");
    148 	    }
    149 	} else
    150 	    event_log(20, "Mixmaster Service stopped");
    151 	CloseHandle(hMustTerminate);
    152 	hMustTerminate = NULL;
    153     } else
    154 	if (hThread)
    155 	    TerminateThread(hThread, 0);
    156     if (hThread)
    157 	CloseHandle(hThread);
    158     hThread = NULL;
    159     ssStatus.dwCurrentState = SERVICE_STOPPED;
    160 } /* service_stop */
    161 
    162 
    163 static int set_stdfiles()
    164 { /* needed for _popen() */
    165     static DWORD std_handles[]={STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
    166     FILE *stdfile[]={stdin, stdout, stderr};
    167     HANDLE hStd;
    168     int fh, stf_fileno;
    169     FILE *fl;
    170 
    171     AllocConsole();
    172     for (stf_fileno=0; stf_fileno<=2; stf_fileno++) {
    173 	hStd = GetStdHandle(std_handles[stf_fileno]);
    174 	if (hStd == INVALID_HANDLE_VALUE)
    175 	    return 0;
    176 	fh = _open_osfhandle((long)std_handles[stf_fileno], (stf_fileno ? _O_WRONLY : _O_RDONLY ) | _O_BINARY);
    177 	dup2(fh, stf_fileno);
    178 	fl = _fdopen(stf_fileno, (stf_fileno ? "wcb" : "rcb" ));
    179 	fflush(stdfile[stf_fileno]);
    180 	memcpy(stdfile[stf_fileno], fl, sizeof(FILE));
    181     }
    182     return 1;
    183 } /* set_stdfiles */
    184 
    185 
    186 static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id)
    187 {
    188     static DWORD dwCheckPoint = 1;
    189     BOOL ret_val;
    190 
    191     if (not_service)
    192 	return TRUE;
    193 
    194     ssStatus.dwCurrentState = current_state;
    195     ssStatus.dwWin32ExitCode = exit_code;
    196     ssStatus.dwWaitHint = wait_hint;
    197     ssStatus.dwControlsAccepted = (current_state == SERVICE_START_PENDING) ?
    198 	0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    199     ssStatus.dwCheckPoint = ((current_state == SERVICE_RUNNING) || (current_state == SERVICE_STOPPED)) ?
    200 	0 : dwCheckPoint++;
    201 
    202     if (!(ret_val = SetServiceStatus(sshStatusHandle, &ssStatus)))
    203 	event_log(id, "SetServiceStatus failed");
    204     return ret_val;
    205 } /* send_status */
    206 
    207 
    208 static void event_log(DWORD id, char *eventmsg)
    209 {
    210     HANDLE  hEventSource;
    211     char    *pStrings[2] = {"", eventmsg};
    212 
    213     if (not_service)
    214 	return;
    215 
    216     if (id > 1000)
    217 	pStrings[0] = GetLastErrorText();
    218 
    219     if (!(hEventSource = RegisterEventSource(NULL, SVCNAME)))
    220 	return;
    221     ReportEvent(hEventSource, (WORD)((id < 1000) ? EVENTLOG_SUCCESS : EVENTLOG_ERROR_TYPE),
    222 	0, id, NULL, 2, 0, pStrings, NULL);
    223     DeregisterEventSource(hEventSource);
    224 } /* event_log */
    225 
    226 
    227 static int run_notservice(int argc, char ** argv)
    228 {
    229     not_service = TRUE;
    230     return mix_main(argc, argv);
    231 } /* run_notservice */
    232 
    233 
    234 static int install_service()
    235 {
    236     SC_HANDLE schService, schSCManager;
    237     char filename[_MAX_PATH+10];
    238 
    239     if (GetModuleFileName(NULL, filename, _MAX_PATH) == 0) {
    240 	printf("Unable to install Mixmaster Service: %s\n", GetLastErrorText());
    241 	return 1;
    242     }
    243     strcat(filename, " --run-svc");
    244 
    245     if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
    246 	printf("OpenSCManager failed: %s\n", GetLastErrorText());
    247 	return 1;
    248     }
    249     schService = CreateService(schSCManager, SVCNAME, SVCDISPLAYNAME,
    250 	SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
    251 	filename, NULL, NULL, NULL, NULL, NULL);
    252 
    253     if (schService) {
    254 	printf("Mixmaster Service installed.\n");
    255 	CloseServiceHandle(schService);
    256     } else {
    257 	printf("CreateService failed: %s\n", GetLastErrorText());
    258     }
    259 
    260     CloseServiceHandle(schSCManager);
    261     return 0;
    262 } /* install_service */
    263 
    264 
    265 static int remove_service()
    266 {
    267     SC_HANDLE schService, schSCManager;
    268     int ret_val = 0;
    269 
    270     if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
    271 	printf("OpenSCManager failed: %s\n", GetLastErrorText());
    272 	return 1;
    273     }
    274     if (!(schService = OpenService(schSCManager, SVCNAME, SERVICE_ALL_ACCESS))) {
    275 	CloseServiceHandle(schSCManager);
    276 	printf("OpenService failed: %s\n", GetLastErrorText());
    277 	return 1;
    278     }
    279     /* try to stop the service */
    280     if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) {
    281 	printf("Stopping Mixmaster Service");
    282 	do {
    283 	    sleep(1);
    284 	    printf(".");
    285 	    QueryServiceStatus(schService, &ssStatus);
    286 	} while (ssStatus.dwCurrentState != SERVICE_STOP_PENDING);
    287 
    288 	if (ssStatus.dwCurrentState == SERVICE_STOPPED)
    289 	    printf("\nMixmaster Service stopped.\n");
    290 	else
    291 	    printf("\n%Mixmaster Service failed to stop.\n");
    292     }
    293 
    294     /* now remove the service */
    295     if (!DeleteService(schService)) {
    296 	ret_val = 1;
    297 	printf("DeleteService failed: %s\n", GetLastErrorText());
    298     } else
    299 	printf("Mixmaster Service removed.\n");
    300 
    301     CloseServiceHandle(schService);
    302     CloseServiceHandle(schSCManager);
    303     return ret_val;
    304 } /* remove_service */
    305 
    306 
    307 static char *GetLastErrorText()
    308 {
    309     static char error_buf[256];
    310     DWORD dwRet, err;
    311     LPSTR lpszTemp = NULL;
    312 
    313     dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
    314 	                  NULL, err=GetLastError(), LANG_NEUTRAL, (LPSTR)&lpszTemp, 0, NULL);
    315 
    316     /* supplied buffer is not long enough */
    317     if (!dwRet || (256 < (long)dwRet+14))
    318 	sprintf(error_buf, "Error (0x%x)", err);
    319     else {
    320 	lpszTemp[lstrlen(lpszTemp)-2] = '\0';
    321 	/* remove cr and newline character */
    322 	sprintf(error_buf, "%s (0x%x)", lpszTemp, err);
    323     }
    324 
    325     if (lpszTemp)
    326 	LocalFree((HLOCAL)lpszTemp);
    327 
    328     return error_buf;
    329 } /* GetLastErrorText */
    330 
    331 #endif /* WIN32SERVICE */