w32svrapi.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /*********************************************************************
  2. *
  3. * File : $Source: /cvsroot/ijbswa/current/w32svrapi.c,v $
  4. *
  5. * Purpose : Win32 Services API for Privoxy.
  6. * Provides the implementation of an Win32 service to
  7. * allow the code to directly register and run as a
  8. * native Windows service application.
  9. *
  10. * Since Win9x/ME platforms don't provide or support
  11. * running programs as services, this code uses runtime
  12. * loading and calling of the Win32 Service API, to
  13. * prevent the possibility of getting "entry point not
  14. * found" type errors on unsupported platforms. This adds
  15. * a little more complexity to the code, but it is worth
  16. * doing to provide that isolation.
  17. *
  18. * Copyright : Written by and Copyright (C) 2003, 2006 members of
  19. * the Privoxy team. https://www.privoxy.org/
  20. *
  21. * Written by and Copyright (C) 2003 Ian Cummings
  22. * <ian_a_c@hotmail.com>
  23. *
  24. * Special thanks to Mates Dolák <matesek@post.cz> for
  25. * some very helpful feedback and suggestions during the
  26. * development of this code.
  27. *
  28. * This program is free software; you can redistribute it
  29. * and/or modify it under the terms of the GNU General
  30. * Public License as published by the Free Software
  31. * Foundation; either version 2 of the License, or (at
  32. * your option) any later version.
  33. *
  34. * This program is distributed in the hope that it will
  35. * be useful, but WITHOUT ANY WARRANTY; without even the
  36. * implied warranty of MERCHANTABILITY or FITNESS FOR A
  37. * PARTICULAR PURPOSE. See the GNU General Public
  38. * License for more details.
  39. *
  40. * The GNU General Public License should be included with
  41. * this file. If not, you can view it at
  42. * http://www.gnu.org/copyleft/gpl.html
  43. * or write to the Free Software Foundation, Inc., 59
  44. * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  45. *
  46. *********************************************************************/
  47. #include "config.h"
  48. #ifdef _WIN32
  49. #include <stdio.h>
  50. #ifndef STRICT
  51. #define STRICT
  52. #endif
  53. #include <windows.h>
  54. #include <process.h>
  55. #ifndef _WIN_CONSOLE
  56. # include "w32log.h"
  57. #endif /* ndef _WIN_CONSOLE */
  58. #include "w32svrapi.h"
  59. /* Only the ANSI Win32 APIs are used at this time. If for some
  60. * reason, we're building under unicode then we must stop
  61. */
  62. #ifdef UNICODE
  63. #error "Privoxy interface to Win32 Services only runs under ANSI builds. Unicode is not supported at present, but you can volunteer for the job if you like! :)"
  64. #endif
  65. /* Default to not running as service, unless the command line says so */
  66. BOOL bRunAsService = FALSE;
  67. /* According to the Win32 docs for CreateService,
  68. * the max length for the service name is 256 chars
  69. */
  70. char szThisServiceName[260];
  71. static BOOL get_service_description(const char *pszServiceName, char *pszDisplayName, DWORD dwDispSize);
  72. static void WINAPI privoxy_w32_service_start(DWORD dw, LPSTR* psz);
  73. static void WINAPI privoxy_w32_service_handler(DWORD dwOpcode);
  74. SERVICE_TABLE_ENTRY w32ServiceDispatchTable[] = {{"", privoxy_w32_service_start}, {NULL, NULL}};
  75. static SERVICE_STATUS_HANDLE hSrv_status = 0;
  76. static SERVICE_STATUS srv_status;
  77. /*********************************************************************
  78. * This function returns TRUE if we are running on an OS that can
  79. * support services, like NT, etc. It returns FALSE for Win9x/ME.
  80. *********************************************************************/
  81. static BOOL HasServiceControlManager()
  82. {
  83. HMODULE hDll;
  84. FARPROC pFunc;
  85. SC_HANDLE hScm;
  86. /* Load the DLL with the SCM functions or return a failure status */
  87. hDll = LoadLibrary("Advapi32.dll");
  88. if (hDll == NULL)
  89. {
  90. printf("Can't load Advapi32.dll -- LoadLibrary failed!\n");
  91. return FALSE;
  92. }
  93. /* Get the address of the ANSI OpenSCManager function, or return a failure status */
  94. pFunc = GetProcAddress(hDll, "OpenSCManagerA");
  95. if (pFunc == NULL)
  96. {
  97. printf("Can't find OpenSCManagerA -- GetProcAddress failed!\n");
  98. FreeLibrary(hDll);
  99. return FALSE;
  100. }
  101. /* Try and connect to the SCM. If it fails check and see if the error
  102. * code is ERROR_CALL_NOT_IMPLEMENTED, which means:
  103. * "This function is not supported on this system."
  104. */
  105. hScm = (SC_HANDLE)(*pFunc)(NULL, NULL, SC_MANAGER_CONNECT);
  106. if (hScm == NULL)
  107. {
  108. DWORD dwErr = GetLastError();
  109. if (dwErr == ERROR_CALL_NOT_IMPLEMENTED)
  110. {
  111. /* Expected error under Win9x/Me, so don't print any debug info
  112. * here as we'll leave that up to the calling function to do
  113. */
  114. FreeLibrary(hDll);
  115. return FALSE;
  116. }
  117. printf("Call to OpenSCManager failed -- GetLastError() returned %lu!\n", dwErr);
  118. FreeLibrary(hDll);
  119. return FALSE;
  120. }
  121. w32_close_service_handle(hScm);
  122. /* OpenSCManager function exists and works, so we're on an NT type platform */
  123. FreeLibrary(hDll);
  124. return TRUE;
  125. } /* -END- HasServiceControlManager */
  126. BOOL CanSystemSupportServices()
  127. {
  128. BOOL bHasScm = HasServiceControlManager();
  129. return bHasScm;
  130. } /* -END- CanSystemSupportServices */
  131. /*********************************************************************
  132. *
  133. * The Service functions are defined in <winsvc.h> which is where
  134. * the declarations used in this file are taken from
  135. *
  136. *********************************************************************/
  137. /*********************************************************************
  138. * Open a connection to the service control manager
  139. *********************************************************************/
  140. SC_HANDLE w32_open_sc_manager(
  141. LPCTSTR lpMachineName, /* computer name */
  142. LPCTSTR lpDatabaseName, /* SCM database name */
  143. DWORD dwDesiredAccess) /* access type */
  144. {
  145. HMODULE hDll = NULL;
  146. SC_HANDLE hScm = NULL;
  147. FARPROC pFunc = NULL;
  148. DWORD dwLastErr = 0;
  149. /* Load the DLL with the SCM functions or return failure */
  150. hDll = LoadLibrary("Advapi32.dll");
  151. if (hDll == NULL)
  152. {
  153. return NULL;
  154. }
  155. /* Get the address of the ANSI OpenSCManager function, or return failure */
  156. pFunc = GetProcAddress(hDll, "OpenSCManagerA");
  157. if (pFunc == NULL)
  158. {
  159. FreeLibrary(hDll);
  160. return NULL;
  161. }
  162. /* Call the SCM function, and save the error code */
  163. hScm = (SC_HANDLE)(*pFunc)(lpMachineName, lpDatabaseName, dwDesiredAccess);
  164. dwLastErr = GetLastError();
  165. /* Release the library and then restore the last error
  166. * code, in case FreeLibrary altered it.
  167. */
  168. FreeLibrary(hDll);
  169. SetLastError(dwLastErr);
  170. return hScm;
  171. } /* -END- w32_open_sc_manager */
  172. BOOL w32_close_service_handle(
  173. SC_HANDLE hSCObject) /* handle to service or SCM object */
  174. {
  175. HMODULE hDll = NULL;
  176. FARPROC pFunc = NULL;
  177. DWORD dwLastErr = 0;
  178. BOOL bRet;
  179. /* Load the DLL with the SCM functions or return a failure status */
  180. hDll = LoadLibrary("Advapi32.dll");
  181. if (hDll == NULL)
  182. {
  183. return FALSE;
  184. }
  185. /* Get the address of the CloseServiceHandle function, or return a failure status */
  186. pFunc = GetProcAddress(hDll, "CloseServiceHandle");
  187. if (pFunc == NULL)
  188. {
  189. FreeLibrary(hDll);
  190. return FALSE;
  191. }
  192. /* Close the handle, and save the error code */
  193. bRet = (BOOL)(*pFunc)(hSCObject);
  194. dwLastErr = GetLastError();
  195. /* Release the library and then restore the last error
  196. * code, in case FreeLibrary altered it.
  197. */
  198. FreeLibrary(hDll);
  199. SetLastError(dwLastErr);
  200. return bRet;
  201. } /* -END- w32_close_service_handle */
  202. /*********************************************************************
  203. * Open a service
  204. *********************************************************************/
  205. SC_HANDLE w32_open_service(
  206. SC_HANDLE hSCManager, /* handle to SCM database */
  207. LPCTSTR lpServiceName, /* service name */
  208. DWORD dwDesiredAccess) /* access */
  209. {
  210. HMODULE hDll = NULL;
  211. SC_HANDLE hSrv = NULL;
  212. FARPROC pFunc = NULL;
  213. DWORD dwLastErr = 0;
  214. /* Load the DLL with the SCM functions or return failure */
  215. hDll = LoadLibrary("Advapi32.dll");
  216. if (hDll == NULL)
  217. {
  218. return NULL;
  219. }
  220. /* Get the address of the ANSI OpenService function, or return failure */
  221. pFunc = GetProcAddress(hDll, "OpenServiceA");
  222. if (pFunc == NULL)
  223. {
  224. FreeLibrary(hDll);
  225. return NULL;
  226. }
  227. /* Call the SCM function, and save the error code */
  228. hSrv = (SC_HANDLE)(*pFunc)(hSCManager, lpServiceName, dwDesiredAccess);
  229. dwLastErr = GetLastError();
  230. /* Release the library and then restore the last error
  231. * code, in case FreeLibrary altered it.
  232. */
  233. FreeLibrary(hDll);
  234. SetLastError(dwLastErr);
  235. return hSrv;
  236. } /* -END- w32_open_service */
  237. SC_HANDLE w32_create_service(
  238. SC_HANDLE hSCManager, /* handle to SCM database */
  239. LPCTSTR lpServiceName, /* name of service to start */
  240. LPCTSTR lpDisplayName, /* display name */
  241. DWORD dwDesiredAccess, /* type of access to service */
  242. DWORD dwServiceType, /* type of service */
  243. DWORD dwStartType, /* when to start service */
  244. DWORD dwErrorControl, /* severity of service failure */
  245. LPCTSTR lpBinaryPathName, /* name of binary file */
  246. LPCTSTR lpLoadOrderGroup, /* name of load ordering group */
  247. LPDWORD lpdwTagId, /* tag identifier */
  248. LPCTSTR lpDependencies, /* array of dependency names */
  249. LPCTSTR lpServiceStartName, /* account name */
  250. LPCTSTR lpPassword) /* account password */
  251. {
  252. HMODULE hDll = NULL;
  253. SC_HANDLE hSrv = NULL;
  254. FARPROC pFunc = NULL;
  255. DWORD dwLastErr = 0;
  256. /* Load the DLL with the SCM functions or return failure */
  257. hDll = LoadLibrary("Advapi32.dll");
  258. if (hDll == NULL)
  259. {
  260. return NULL;
  261. }
  262. /* Get the address of the ANSI CreateService function, or return failure */
  263. pFunc = GetProcAddress(hDll, "CreateServiceA");
  264. if (pFunc == NULL)
  265. {
  266. FreeLibrary(hDll);
  267. return NULL;
  268. }
  269. /* Call the SCM function, and save the error code */
  270. hSrv = (SC_HANDLE)(*pFunc)(hSCManager, /* handle to SCM database */
  271. lpServiceName, /* name of service to start */
  272. lpDisplayName, /* display name */
  273. dwDesiredAccess, /* type of access to service */
  274. dwServiceType, /* type of service */
  275. dwStartType, /* when to start service */
  276. dwErrorControl, /* severity of service failure */
  277. lpBinaryPathName, /* name of binary file */
  278. lpLoadOrderGroup, /* name of load ordering group */
  279. lpdwTagId, /* tag identifier */
  280. lpDependencies, /* array of dependency names */
  281. lpServiceStartName, /* account name */
  282. lpPassword); /* account password */
  283. dwLastErr = GetLastError();
  284. /* Release the library and then restore the last error
  285. * code, in case FreeLibrary altered it.
  286. */
  287. FreeLibrary(hDll);
  288. SetLastError(dwLastErr);
  289. return hSrv;
  290. } /* -END- w32_create_service */
  291. BOOL w32_delete_service(
  292. SC_HANDLE hService) /* handle to service */
  293. {
  294. HMODULE hDll = NULL;
  295. FARPROC pFunc = NULL;
  296. DWORD dwLastErr = 0;
  297. BOOL bRet;
  298. /* Load the DLL with the SCM functions or return a failure status */
  299. hDll = LoadLibrary("Advapi32.dll");
  300. if (hDll == NULL)
  301. {
  302. return FALSE;
  303. }
  304. /* Get the address of the DeleteService function, or return a failure status */
  305. pFunc = GetProcAddress(hDll, "DeleteService");
  306. if (pFunc == NULL)
  307. {
  308. FreeLibrary(hDll);
  309. return FALSE;
  310. }
  311. /* Close the handle, and save the error code */
  312. bRet = (BOOL)(*pFunc)(hService);
  313. dwLastErr = GetLastError();
  314. /* Release the library and then restore the last error
  315. * code, in case FreeLibrary altered it.
  316. */
  317. FreeLibrary(hDll);
  318. SetLastError(dwLastErr);
  319. return bRet;
  320. } /* -END- w32_delete_service */
  321. BOOL w32_query_service_config(
  322. SC_HANDLE hService, /* handle to service */
  323. LPQUERY_SERVICE_CONFIG lpServiceConfig, /* buffer */
  324. DWORD cbBufSize, /* size of buffer */
  325. LPDWORD pcbBytesNeeded) /* bytes needed */
  326. {
  327. HMODULE hDll = NULL;
  328. FARPROC pFunc = NULL;
  329. DWORD dwLastErr = 0;
  330. BOOL bRet;
  331. /* Load the DLL with the SCM functions or return a failure status */
  332. hDll = LoadLibrary("Advapi32.dll");
  333. if (hDll == NULL)
  334. {
  335. return FALSE;
  336. }
  337. /* Get the address of the QueryServiceConfig function, or return a failure status */
  338. pFunc = GetProcAddress(hDll, "QueryServiceConfigA");
  339. if (pFunc == NULL)
  340. {
  341. FreeLibrary(hDll);
  342. return FALSE;
  343. }
  344. /* Close the handle, and save the error code */
  345. bRet = (BOOL)(*pFunc)(hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
  346. dwLastErr = GetLastError();
  347. /* Release the library and then restore the last error
  348. * code, in case FreeLibrary altered it.
  349. */
  350. FreeLibrary(hDll);
  351. SetLastError(dwLastErr);
  352. return bRet;
  353. } /* -END- w32_query_service_config */
  354. BOOL w32_start_service_ctrl_dispatcher(
  355. CONST LPSERVICE_TABLE_ENTRY lpServiceTable) /* service table */
  356. {
  357. HMODULE hDll = NULL;
  358. FARPROC pFunc = NULL;
  359. DWORD dwLastErr = 0;
  360. BOOL bRet;
  361. /* Load the DLL with the SCM functions or return a failure status */
  362. hDll = LoadLibrary("Advapi32.dll");
  363. if (hDll == NULL)
  364. {
  365. return FALSE;
  366. }
  367. /* Get the address of the StartServiceCtrlDispatcher function, or return a failure status */
  368. pFunc = GetProcAddress(hDll, "StartServiceCtrlDispatcherA");
  369. if (pFunc == NULL)
  370. {
  371. FreeLibrary(hDll);
  372. return FALSE;
  373. }
  374. /* Close the handle, and save the error code */
  375. bRet = (BOOL)(*pFunc)(lpServiceTable);
  376. dwLastErr = GetLastError();
  377. /* Release the library and then restore the last error
  378. * code, in case FreeLibrary altered it.
  379. */
  380. FreeLibrary(hDll);
  381. SetLastError(dwLastErr);
  382. return bRet;
  383. } /* -END- w32_start_service_ctrl_dispatcher */
  384. SERVICE_STATUS_HANDLE w32_register_service_ctrl_handler(
  385. LPCTSTR lpServiceName, /* service name */
  386. LPHANDLER_FUNCTION lpHandlerProc) /* handler function */
  387. {
  388. HMODULE hDll = NULL;
  389. FARPROC pFunc = NULL;
  390. DWORD dwLastErr = 0;
  391. SERVICE_STATUS_HANDLE hServStat = (SERVICE_STATUS_HANDLE)0;
  392. /* Load the DLL with the SCM functions or return a failure status */
  393. hDll = LoadLibrary("Advapi32.dll");
  394. if (hDll == NULL)
  395. {
  396. return hServStat;
  397. }
  398. /* Get the address of the RegisterServiceCtrlHandler function, or return a failure status */
  399. pFunc = GetProcAddress(hDll, "RegisterServiceCtrlHandlerA");
  400. if (pFunc == NULL)
  401. {
  402. FreeLibrary(hDll);
  403. return hServStat;
  404. }
  405. /* Close the handle, and save the error code */
  406. hServStat = (SERVICE_STATUS_HANDLE)(*pFunc)(lpServiceName, lpHandlerProc);
  407. dwLastErr = GetLastError();
  408. /* Release the library and then restore the last error
  409. * code, in case FreeLibrary altered it.
  410. */
  411. FreeLibrary(hDll);
  412. SetLastError(dwLastErr);
  413. return hServStat;
  414. } /* -END- w32_register_service_ctrl_handler */
  415. BOOL w32_set_service_status(
  416. SERVICE_STATUS_HANDLE hServiceStatus, /* service status handle */
  417. LPSERVICE_STATUS lpServiceStatus) /* status buffer */
  418. {
  419. HMODULE hDll = NULL;
  420. FARPROC pFunc = NULL;
  421. DWORD dwLastErr = 0;
  422. BOOL bRet;
  423. /* Load the DLL with the SCM functions or return a failure status */
  424. hDll = LoadLibrary("Advapi32.dll");
  425. if (hDll == NULL)
  426. {
  427. return FALSE;
  428. }
  429. /* Get the address of the SetServiceStatus function, or return a failure status */
  430. pFunc = GetProcAddress(hDll, "SetServiceStatus");
  431. if (pFunc == NULL)
  432. {
  433. FreeLibrary(hDll);
  434. return FALSE;
  435. }
  436. /* Close the handle, and save the error code */
  437. bRet = (BOOL)(*pFunc)(hServiceStatus, lpServiceStatus);
  438. dwLastErr = GetLastError();
  439. /* Release the library and then restore the last error
  440. * code, in case FreeLibrary altered it.
  441. */
  442. FreeLibrary(hDll);
  443. SetLastError(dwLastErr);
  444. return bRet;
  445. } /* -END- w32_set_service_status */
  446. static void display_win32_msg(BOOL bIsError, char *msg)
  447. {
  448. #ifdef _WIN_CONSOLE
  449. printf("%s", msg);
  450. #else
  451. if (bIsError)
  452. {
  453. MessageBox(NULL, msg, "Privoxy Error",
  454. MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);
  455. }
  456. else
  457. {
  458. MessageBox(NULL, msg, "Privoxy Information",
  459. MB_OK | MB_ICONINFORMATION | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);
  460. }
  461. #endif
  462. } /* -END- display_win32_msg */
  463. static BOOL get_service_description(const char *pszServiceName, char *pszDisplayName, DWORD dwDispSize)
  464. {
  465. /*********************************************************************
  466. * Create a simple display name
  467. *********************************************************************/
  468. strcpy(pszDisplayName, "Privoxy (");
  469. strncat(pszDisplayName, pszServiceName, dwDispSize - strlen(pszDisplayName) - 2);
  470. strcat(pszDisplayName, ")");
  471. return TRUE;
  472. }
  473. BOOL install_service(const char *service_name)
  474. {
  475. char szModule[(MAX_PATH*2)+1];
  476. char szDisplayName[MAX_PATH+2];
  477. SC_HANDLE hSCM;
  478. SC_HANDLE hService;
  479. /*********************************************************************
  480. * First check if this system can support a service architecture
  481. *********************************************************************/
  482. if (!CanSystemSupportServices())
  483. {
  484. display_win32_msg(TRUE, "This system doesn't support installing Privoxy as a service.\nWinNT/2000/XP are required for this feature.\n");
  485. return FALSE;
  486. }
  487. /* Use a default service name if none was supplied */
  488. if ((service_name == NULL) || (strlen(service_name) == 0))
  489. {
  490. service_name = "privoxy";
  491. }
  492. /*********************************************************************
  493. * Open a handle to the Service Control Manager with full access rights
  494. *********************************************************************/
  495. hSCM = w32_open_sc_manager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  496. if (hSCM == NULL)
  497. {
  498. display_win32_msg(TRUE, "Can't open Service Control Manager - Service install failed!\n Administrator rights are required to create a service.\n");
  499. return FALSE;
  500. }
  501. /*********************************************************************
  502. * Work out the full image path plus command line for the service
  503. * We'll temporarily use szDisplayName as a second buffer.
  504. *********************************************************************/
  505. GetModuleFileName(NULL, szDisplayName, MAX_PATH);
  506. sprintf(szModule, "\"%s\" --service", szDisplayName);
  507. /*********************************************************************
  508. * Get the display name for the service
  509. *********************************************************************/
  510. get_service_description(service_name, szDisplayName, sizeof(szDisplayName)/sizeof(char));
  511. /*********************************************************************
  512. * Create the service
  513. *********************************************************************/
  514. hService = w32_create_service(hSCM,
  515. service_name, /* the internal service name */
  516. szDisplayName, /* the display name */
  517. SERVICE_ALL_ACCESS, /* get full access during creation */
  518. SERVICE_WIN32_OWN_PROCESS /* run in our own process */
  519. #ifndef _WIN_CONSOLE
  520. + SERVICE_INTERACTIVE_PROCESS /* GUI also wants interactive rights */
  521. #endif
  522. ,
  523. SERVICE_DEMAND_START, /* For now, only start when asked to */
  524. SERVICE_ERROR_NORMAL, /* Normal error handling by the SCM */
  525. szModule, /* The executable service file */
  526. NULL, /* No load order info needed */
  527. NULL, /* No load order info needed */
  528. NULL, /* No dependencies */
  529. NULL, /* Default to LocalSystem... */
  530. NULL); /* ...which doesn't require a password */
  531. if (hService == NULL)
  532. {
  533. display_win32_msg(TRUE, "Can't install service!\n");
  534. w32_close_service_handle(hSCM);
  535. return FALSE;
  536. }
  537. display_win32_msg(FALSE, "Service was successfully created.\n*** IMPORTANT NOTE: You should now use the Services control panel to\n*** configure the startup type and user account details for the service.\n\n");
  538. /* tidy up */
  539. w32_close_service_handle(hService);
  540. w32_close_service_handle(hSCM);
  541. return TRUE;
  542. } /* -END- install_service */
  543. BOOL uninstall_service(const char *service_name)
  544. {
  545. char szDisplayName[MAX_PATH+2];
  546. SC_HANDLE hSCM;
  547. SC_HANDLE hService;
  548. BOOL bResult = FALSE;
  549. /*********************************************************************
  550. * First check if this system can support a service architecture
  551. *********************************************************************/
  552. if (!CanSystemSupportServices())
  553. {
  554. display_win32_msg(TRUE, "This system doesn't support installing Privoxy as a service.\nWinNT/2000/XP are required for this feature.\n");
  555. return FALSE;
  556. }
  557. /* Use a default service name if none was supplied */
  558. if ((service_name == NULL) || (strlen(service_name) == 0))
  559. {
  560. service_name = "privoxy";
  561. }
  562. /*********************************************************************
  563. * Open a handle to the Service Control Manager with full access rights
  564. *********************************************************************/
  565. hSCM = w32_open_sc_manager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  566. if (hSCM == NULL)
  567. {
  568. display_win32_msg(TRUE, "Can't open Service Control Manager - Service uninstall failed!\n Administrator rights are required to delete a service.\n");
  569. return FALSE;
  570. }
  571. /*********************************************************************
  572. * Get the display name for the service
  573. *********************************************************************/
  574. get_service_description(service_name, szDisplayName, sizeof(szDisplayName)/sizeof(char));
  575. /*********************************************************************
  576. * Open and then delete the service
  577. *********************************************************************/
  578. hService = w32_open_service(hSCM, service_name, DELETE);
  579. if (hService == NULL)
  580. {
  581. display_win32_msg(TRUE, "Can't open service for delete access rights!\n");
  582. w32_close_service_handle(hSCM);
  583. return FALSE;
  584. }
  585. if (w32_delete_service(hService))
  586. {
  587. display_win32_msg(FALSE, "Service was deleted successfully.\n");
  588. bResult = TRUE;
  589. }
  590. else
  591. {
  592. display_win32_msg(TRUE, "Service could not be deleted!\n");
  593. bResult = FALSE;
  594. }
  595. w32_close_service_handle(hService);
  596. w32_close_service_handle(hSCM);
  597. return bResult;
  598. } /* -END- uninstall_service */
  599. /*********************************************************************
  600. *
  601. * Function : privoxy_w32_service_start
  602. *
  603. * Description : This is the entry point function for the service.
  604. * In other words, it's the ServiceMain function.
  605. *
  606. * Parameters : Defined by the Win32 API, but not used here
  607. *
  608. * Returns : void
  609. *
  610. *********************************************************************/
  611. static void WINAPI privoxy_w32_service_start(DWORD dw, LPSTR* pszArgs)
  612. {
  613. int child_id;
  614. /* Arg zero is always the service name, and we need to
  615. * know it when we call RegisterServiceCtrlHandler.
  616. */
  617. strcpy(szThisServiceName, pszArgs[0]);
  618. /* Tell the SCM we are running */
  619. srv_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  620. srv_status.dwCurrentState = SERVICE_RUNNING;
  621. srv_status.dwCheckPoint = 0;
  622. srv_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  623. srv_status.dwWin32ExitCode = NO_ERROR;
  624. srv_status.dwServiceSpecificExitCode = 0;
  625. srv_status.dwWaitHint = 0;
  626. hSrv_status = w32_register_service_ctrl_handler(szThisServiceName, privoxy_w32_service_handler);
  627. if (!hSrv_status)
  628. {
  629. return;
  630. }
  631. w32_set_service_status(hSrv_status, &srv_status);
  632. #ifndef FEATURE_PTHREAD
  633. /* NOTE: a cygwin cross-compiler build for --host=i686-w64-mingw32 must disable POSIX threading - eg
  634. * ./configure --host=i686-w64-mingw32 --disable-pthread
  635. */
  636. child_id = _beginthread(w32_service_listen_loop, 0, NULL);
  637. if (child_id > 0)
  638. #else
  639. #error "FIXME: Do pthread stuff here!"
  640. #endif
  641. {
  642. w32_set_service_status(hSrv_status, &srv_status);
  643. }
  644. else
  645. {
  646. srv_status.dwCurrentState = SERVICE_STOPPED;
  647. srv_status.dwCheckPoint = 0;
  648. srv_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  649. srv_status.dwServiceSpecificExitCode = ERROR_SERVICE_NO_THREAD;
  650. w32_set_service_status(hSrv_status, &srv_status);
  651. }
  652. }
  653. /*********************************************************************
  654. *
  655. * Function : w32_set_service_cwd
  656. *
  657. * Description : Simple function to change the current directory to
  658. * the same location as the service executable.
  659. *
  660. * Parameters : void
  661. *
  662. * Returns : void
  663. *
  664. *********************************************************************/
  665. void w32_set_service_cwd(void)
  666. {
  667. char exe_name[MAX_PATH+1];
  668. char dir_name[MAX_PATH+1];
  669. char *pszFile = NULL;
  670. /* Get the exe name and path of the service */
  671. if (GetModuleFileName(NULL, exe_name, MAX_PATH))
  672. {
  673. /* Ask the API to tell us where the filename portion starts */
  674. if (GetFullPathName(exe_name, MAX_PATH, dir_name, &pszFile))
  675. {
  676. /* remove the filename from the string */
  677. if (pszFile != NULL)
  678. {
  679. *pszFile = '\0';
  680. /* We have just a directory path now, so make it current */
  681. SetCurrentDirectory(dir_name);
  682. }
  683. }
  684. }
  685. }
  686. /*********************************************************************
  687. *
  688. * Function : w32_service_exit_notify
  689. *
  690. * Description : This is a simple atexit function that is called by the
  691. * C runtime after exit has been called. It allows the
  692. * service code to detect when the app is about to die and
  693. * send an quick notification to the SCM that the service
  694. * now stopped.
  695. *
  696. * Parameters : void
  697. *
  698. * Returns : void
  699. *
  700. *********************************************************************/
  701. void w32_service_exit_notify(void)
  702. {
  703. if (hSrv_status != 0)
  704. {
  705. if (srv_status.dwCurrentState != SERVICE_STOPPED)
  706. {
  707. srv_status.dwCurrentState = SERVICE_STOPPED;
  708. srv_status.dwCheckPoint = 0;
  709. srv_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  710. srv_status.dwServiceSpecificExitCode = ERROR_PROCESS_ABORTED;
  711. w32_set_service_status(hSrv_status, &srv_status);
  712. }
  713. }
  714. }
  715. static void w32_mini_exit(void *p)
  716. {
  717. Sleep(100);
  718. #ifdef _WIN_CONSOLE
  719. exit(0);
  720. #else
  721. PostMessage(g_hwndLogFrame, WM_CLOSE, 0, 0);
  722. #endif /* def _WIN_CONSOLE */
  723. }
  724. /*********************************************************************
  725. *
  726. * Function : privoxy_w32_service_handler
  727. *
  728. * Description : This is the control message handler function for
  729. * the service.
  730. *
  731. * Parameters : dwOpcode
  732. * requested control code sent by SCM
  733. *
  734. * Returns : void
  735. *
  736. *********************************************************************/
  737. static void WINAPI privoxy_w32_service_handler(DWORD dwOpcode)
  738. {
  739. switch(dwOpcode)
  740. {
  741. case SERVICE_CONTROL_STOP:
  742. /* We've stopped
  743. */
  744. srv_status.dwCurrentState = SERVICE_STOPPED;
  745. srv_status.dwCheckPoint = 0;
  746. srv_status.dwWin32ExitCode = NO_ERROR;
  747. srv_status.dwServiceSpecificExitCode = 0;
  748. /* Maybe there is a more friendly way to stop, but this will do for now! */
  749. w32_set_service_status(hSrv_status, &srv_status);
  750. /* During testing, I kept getting error 109 (ERROR_BROKEN_PIPE) and
  751. * as far as the SCM was concerned the service was still stopping,
  752. * even after the process had disappeared.
  753. *
  754. * It seems that if we call exit in the ServiceMain thread, it causes
  755. * the SCM to not receive the status we sent in the line above. The
  756. * simple fix was to create a new thread to actually call exit for us
  757. * whilst this thread continues and returns to its caller.
  758. */
  759. if (_beginthread(w32_mini_exit, 0, NULL) < 0)
  760. {
  761. /* we failed to create the exit thread, so just force an exit here
  762. * and the SCM will just have to go and whistle!
  763. */
  764. exit(0);
  765. }
  766. break;
  767. default:
  768. break;
  769. }
  770. w32_set_service_status(hSrv_status, &srv_status);
  771. }
  772. #endif /* ifdef _WIN32 */