]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - win/win32service.cpp
make service log on as local service builtin account again. There was no issue with...
[user/henk/code/inspircd.git] / win / win32service.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */\r
13 \r
14 #include <windows.h>\r
15 #include <stdlib.h>\r
16 #include <string.h>\r
17 #include <stdio.h>\r
18 \r
19 extern int smain(int argc, char** argv);\r
20 \r
21 static SERVICE_STATUS_HANDLE serviceStatusHandle;\r
22 static HANDLE hThreadEvent;\r
23 static HANDLE killServiceEvent;\r
24 static int serviceCurrentStatus;\r
25 \r
26 // This is used to define ChangeServiceConf2() as we can't link\r
27 // directly against this symbol (see below where it is used)\r
28 typedef BOOL (CALLBACK* SETSERVDESC)(SC_HANDLE,DWORD,LPVOID);\r
29 \r
30 SETSERVDESC ChangeServiceConf;          // A function pointer for dynamic linking tricks\r
31 \r
32 \r
33 void KillService()\r
34 {\r
35         /* FIXME: This should set a flag in the mainloop for shutting down */\r
36         SetEvent(hThreadEvent);\r
37         Sleep(2000);\r
38         SetEvent(killServiceEvent);\r
39 }\r
40 \r
41 DWORD WINAPI WorkerThread(LPDWORD param)\r
42 {\r
43         // *** REAL MAIN HERE ***\r
44         char modname[MAX_PATH];\r
45         GetModuleFileName(NULL, modname, sizeof(modname));\r
46         char* argv[] = { modname, "--nofork", "--debug" };\r
47         smain(3, argv);\r
48         KillService();\r
49         return 0;\r
50 }\r
51 \r
52 void StartServiceThread()\r
53 {\r
54         DWORD dwd;\r
55         CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkerThread,NULL,0,&dwd);\r
56 }\r
57 \r
58 \r
59 BOOL UpdateSCMStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint)\r
60 {\r
61         BOOL success;\r
62         SERVICE_STATUS serviceStatus;\r
63         serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\r
64         serviceStatus.dwCurrentState = dwCurrentState;\r
65 \r
66         if (dwCurrentState == SERVICE_START_PENDING)\r
67         {\r
68                 serviceStatus.dwControlsAccepted = 0;\r
69         }\r
70         else\r
71         {\r
72                 serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;\r
73         }\r
74 \r
75         if (dwServiceSpecificExitCode == 0)\r
76         {\r
77                 serviceStatus.dwWin32ExitCode = dwWin32ExitCode;\r
78         }\r
79         else\r
80         {\r
81                 serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;\r
82         }\r
83         serviceStatus.dwServiceSpecificExitCode =   dwServiceSpecificExitCode;\r
84         serviceStatus.dwCheckPoint = dwCheckPoint;\r
85         serviceStatus.dwWaitHint = dwWaitHint;\r
86 \r
87         success = SetServiceStatus (serviceStatusHandle, &serviceStatus);\r
88         if (!success)\r
89         {\r
90                 KillService();\r
91         }\r
92         return success;\r
93 }\r
94 \r
95 \r
96 void terminateService (int code, int wincode)\r
97 {\r
98         UpdateSCMStatus(SERVICE_STOPPED,wincode?wincode:ERROR_SERVICE_SPECIFIC_ERROR,(wincode)?0:code,0,0);\r
99         return;\r
100 }\r
101 \r
102 \r
103 VOID ServiceCtrlHandler (DWORD controlCode)\r
104 {\r
105         switch(controlCode)\r
106         {\r
107                 case SERVICE_CONTROL_INTERROGATE:\r
108                 break;\r
109                 case SERVICE_CONTROL_SHUTDOWN:\r
110                 case SERVICE_CONTROL_STOP:\r
111                         serviceCurrentStatus = SERVICE_STOP_PENDING;\r
112                         UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);\r
113                         KillService();\r
114                         UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);\r
115                         return;\r
116                 default:\r
117                 break;\r
118         }\r
119         UpdateSCMStatus(serviceCurrentStatus, NO_ERROR, 0, 0, 0);\r
120 }\r
121 \r
122 \r
123 VOID ServiceMain(DWORD argc, LPTSTR *argv)\r
124 {\r
125         BOOL success;\r
126         DWORD type=0, size=0;\r
127 \r
128         serviceStatusHandle = RegisterServiceCtrlHandler("InspIRCd", (LPHANDLER_FUNCTION)ServiceCtrlHandler);\r
129         if (!serviceStatusHandle)\r
130         {\r
131                 terminateService(1,GetLastError());\r
132                 return;\r
133         }\r
134 \r
135         success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 1000);\r
136         if (!success)\r
137         {\r
138                 terminateService(2,GetLastError());\r
139                 return;\r
140         }\r
141 \r
142         killServiceEvent = CreateEvent(NULL,true,false,NULL);\r
143         hThreadEvent = CreateEvent(NULL,true,false,NULL);\r
144 \r
145         if (!killServiceEvent || !hThreadEvent)\r
146         {\r
147                 terminateService(99,GetLastError());\r
148                 return;\r
149         }\r
150 \r
151         success = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);\r
152         if (!success)\r
153         {\r
154                 terminateService(2,GetLastError());\r
155                 return;\r
156         }\r
157 \r
158         StartServiceThread();\r
159         serviceCurrentStatus = SERVICE_RUNNING;\r
160         success = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);\r
161         if (!success)\r
162         {\r
163                 terminateService(6,GetLastError());\r
164                 return;\r
165         }\r
166         WaitForSingleObject (killServiceEvent, INFINITE);\r
167 }\r
168 \r
169 void InstallService(void)\r
170 {\r
171         SC_HANDLE myService, scm;\r
172         SERVICE_DESCRIPTION svDesc;\r
173         HINSTANCE advapi32;\r
174 \r
175         char modname[MAX_PATH];\r
176         GetModuleFileName(NULL, modname, sizeof(modname));\r
177 \r
178         scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
179         if (!scm)\r
180         {\r
181                 printf("Unable to open service control manager: %d\n", GetLastError());\r
182                 return;\r
183         }\r
184 \r
185         myService = CreateService(scm,"InspIRCd","Inspire IRC Daemon", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,\r
186                 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, modname, 0, 0, 0, NULL, NULL);\r
187 \r
188         if (!myService)\r
189         {\r
190                 printf("Unable to create service: %d\n", GetLastError());\r
191                 CloseServiceHandle(scm);\r
192                 return;\r
193         }\r
194 \r
195         // *** Set service description ***\r
196         // this is supported from 5.0 (win2k) onwards only, so we can't link to the definition of\r
197         // this function in advapi32.lib, otherwise the program will not run on windows NT 4. We\r
198         // must use LoadLibrary and GetProcAddress to export the function name from advapi32.dll\r
199         advapi32 = LoadLibrary("advapi32.dll");\r
200         if (advapi32)\r
201         {\r
202                 ChangeServiceConf = (SETSERVDESC)GetProcAddress(advapi32,"ChangeServiceConfig2A");\r
203                 if (ChangeServiceConf)\r
204                 {\r
205                         char desc[] = "The Inspire Internet Relay Chat Daemon hosts IRC channels and conversations. \\r
206                                       If this service is stopped, the IRC server will not run.";\r
207                         svDesc.lpDescription = desc;\r
208                         BOOL success = ChangeServiceConf(myService,SERVICE_CONFIG_DESCRIPTION, &svDesc);\r
209                         if (!success)\r
210                         {\r
211                                 printf("Unable to set service description: %d\n", GetLastError());\r
212                                 CloseServiceHandle(myService);\r
213                                 CloseServiceHandle(scm);\r
214                                 return;\r
215                         }\r
216                 }\r
217                 FreeLibrary(advapi32);\r
218         }\r
219 \r
220         printf("Service installed.\n");\r
221         CloseServiceHandle(myService);\r
222         CloseServiceHandle(scm);\r
223 }\r
224 \r
225 void RemoveService(void)\r
226 {\r
227         SC_HANDLE myService, scm;\r
228 \r
229         scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
230         if (!scm)\r
231         {\r
232                 printf("Unable to open service control manager: %d\n", GetLastError());\r
233                 return;\r
234         }\r
235 \r
236         myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);\r
237         if (!myService)\r
238         {\r
239                 printf("Unable to open service: %d\n", GetLastError());\r
240                 CloseServiceHandle(scm);\r
241                 return;\r
242         }\r
243 \r
244         if (!DeleteService(myService))\r
245         {\r
246                 printf("Unable to delete service: %d\n", GetLastError());\r
247                 CloseServiceHandle(myService);\r
248                 CloseServiceHandle(scm);\r
249                 return;\r
250         }\r
251 \r
252         printf("Service removed.\n");\r
253         CloseServiceHandle(myService);\r
254         CloseServiceHandle(scm);\r
255 }\r
256 \r
257 /* In windows, our main() flows through here, before calling the 'real' main, smain() in inspircd.cpp */\r
258 int main(int argc, char** argv)\r
259 {\r
260         /* Check for parameters */\r
261         if (argc > 1)\r
262         {\r
263                 if (!_stricmp(argv[1], "--installservice"))\r
264                 {\r
265                         InstallService();\r
266                         return 0;\r
267                 }\r
268                 else if (!_stricmp(argv[1], "--removeservice"))\r
269                 {\r
270                         RemoveService();\r
271                         return 0;\r
272                 }\r
273         }\r
274 \r
275         /* First, check if the service is installed.\r
276          * if it is not, or we're starting as non-administrator,\r
277          * just call smain() and start as normal non-service\r
278          * process.\r
279          */\r
280         SC_HANDLE myService, scm;\r
281         scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);\r
282         if (scm)\r
283         {\r
284                 myService = OpenService(scm,"InspIRCd",SERVICE_ALL_ACCESS);\r
285                 if (!myService)\r
286                 {\r
287                         /* Service not installed or no permission to modify it */\r
288                         CloseServiceHandle(scm);\r
289                         smain(argc, argv);\r
290                 }\r
291         }\r
292         else\r
293         {\r
294                 /* Not enough privileges to open the SCM */\r
295                 smain(argc, argv);\r
296         }\r
297 \r
298         CloseServiceHandle(myService);\r
299         CloseServiceHandle(scm);\r
300 \r
301         /* If we get here, we know the service is installed so we can start it */\r
302 \r
303         SERVICE_TABLE_ENTRY serviceTable[] =\r
304         {\r
305                 {"InspIRCd", (LPSERVICE_MAIN_FUNCTION) ServiceMain },\r
306                 {NULL, NULL}\r
307         };\r
308 \r
309         StartServiceCtrlDispatcher(serviceTable);\r
310         return 0;\r
311 }\r