rpc.c 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171
  1. /*
  2. * Services.exe - RPC functions
  3. *
  4. * Copyright 2007 Google (Mikolaj Zalewski)
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #define WIN32_LEAN_AND_MEAN
  21. #define NONAMELESSSTRUCT
  22. #define NONAMELESSUNION
  23. #include <stdarg.h>
  24. #include <windows.h>
  25. #include <winternl.h>
  26. #include <winsvc.h>
  27. #include <ntsecapi.h>
  28. #include <rpc.h>
  29. #include "wine/list.h"
  30. #include "wine/debug.h"
  31. #include "services.h"
  32. #include "svcctl.h"
  33. extern HANDLE CDECL __wine_make_process_system(void);
  34. WINE_DEFAULT_DEBUG_CHANNEL(service);
  35. static const GENERIC_MAPPING g_scm_generic =
  36. {
  37. (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
  38. (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
  39. (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
  40. SC_MANAGER_ALL_ACCESS
  41. };
  42. static const GENERIC_MAPPING g_svc_generic =
  43. {
  44. (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
  45. (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
  46. (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
  47. SERVICE_ALL_ACCESS
  48. };
  49. typedef enum
  50. {
  51. SC_HTYPE_DONT_CARE = 0,
  52. SC_HTYPE_MANAGER,
  53. SC_HTYPE_SERVICE,
  54. SC_HTYPE_NOTIFY
  55. } SC_HANDLE_TYPE;
  56. struct sc_handle
  57. {
  58. SC_HANDLE_TYPE type;
  59. DWORD access;
  60. };
  61. struct sc_manager_handle /* service control manager handle */
  62. {
  63. struct sc_handle hdr;
  64. struct scmdatabase *db;
  65. };
  66. struct sc_notify_handle
  67. {
  68. struct sc_handle hdr;
  69. HANDLE event;
  70. DWORD notify_mask;
  71. LONG ref;
  72. SC_RPC_NOTIFY_PARAMS_LIST *params_list;
  73. };
  74. struct sc_service_handle /* service handle */
  75. {
  76. struct sc_handle hdr;
  77. struct list entry;
  78. BOOL status_notified;
  79. struct service_entry *service_entry;
  80. struct sc_notify_handle *notify;
  81. };
  82. static void sc_notify_retain(struct sc_notify_handle *notify)
  83. {
  84. InterlockedIncrement(&notify->ref);
  85. }
  86. static void sc_notify_release(struct sc_notify_handle *notify)
  87. {
  88. ULONG r = InterlockedDecrement(&notify->ref);
  89. if (r == 0)
  90. {
  91. CloseHandle(notify->event);
  92. HeapFree(GetProcessHeap(), 0, notify->params_list);
  93. HeapFree(GetProcessHeap(), 0, notify);
  94. }
  95. }
  96. struct sc_lock
  97. {
  98. struct scmdatabase *db;
  99. };
  100. static const WCHAR emptyW[] = {0};
  101. static PTP_CLEANUP_GROUP cleanup_group;
  102. HANDLE exit_event;
  103. static void CALLBACK group_cancel_callback(void *object, void *userdata)
  104. {
  105. struct process_entry *process = object;
  106. release_process(process);
  107. }
  108. static void CALLBACK terminate_callback(TP_CALLBACK_INSTANCE *instance, void *context,
  109. TP_WAIT *wait, TP_WAIT_RESULT result)
  110. {
  111. struct process_entry *process = context;
  112. if (result == WAIT_TIMEOUT) process_terminate(process);
  113. release_process(process);
  114. CloseThreadpoolWait(wait);
  115. }
  116. static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
  117. {
  118. TP_CALLBACK_ENVIRON environment;
  119. LARGE_INTEGER timestamp;
  120. TP_WAIT *wait;
  121. FILETIME ft;
  122. memset(&environment, 0, sizeof(environment));
  123. environment.Version = 1;
  124. environment.CleanupGroup = cleanup_group;
  125. environment.CleanupGroupCancelCallback = group_cancel_callback;
  126. timestamp.QuadPart = (ULONGLONG)timeout * -10000;
  127. ft.dwLowDateTime = timestamp.u.LowPart;
  128. ft.dwHighDateTime = timestamp.u.HighPart;
  129. if ((wait = CreateThreadpoolWait(terminate_callback, grab_process(process), &environment)))
  130. SetThreadpoolWait(wait, process->process, &ft);
  131. else
  132. release_process(process);
  133. }
  134. static void CALLBACK shutdown_callback(TP_CALLBACK_INSTANCE *instance, void *context)
  135. {
  136. struct process_entry *process = context;
  137. DWORD result;
  138. result = WaitForSingleObject(process->control_mutex, 30000);
  139. if (result == WAIT_OBJECT_0)
  140. {
  141. process_send_control(process, FALSE, emptyW, SERVICE_CONTROL_STOP, NULL, 0, &result);
  142. ReleaseMutex(process->control_mutex);
  143. }
  144. release_process(process);
  145. }
  146. static void shutdown_shared_process(struct process_entry *process)
  147. {
  148. TP_CALLBACK_ENVIRON environment;
  149. struct service_entry *service;
  150. struct scmdatabase *db = process->db;
  151. scmdatabase_lock(db);
  152. LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
  153. {
  154. if (service->process != process) continue;
  155. service->status.dwCurrentState = SERVICE_STOP_PENDING;
  156. }
  157. scmdatabase_unlock(db);
  158. memset(&environment, 0, sizeof(environment));
  159. environment.Version = 1;
  160. environment.CleanupGroup = cleanup_group;
  161. environment.CleanupGroupCancelCallback = group_cancel_callback;
  162. if (!TrySubmitThreadpoolCallback(shutdown_callback, grab_process(process), &environment))
  163. release_process(process);
  164. }
  165. static void free_service_strings(struct service_entry *old, struct service_entry *new)
  166. {
  167. QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
  168. QUERY_SERVICE_CONFIGW *new_cfg = &new->config;
  169. if (old_cfg->lpBinaryPathName != new_cfg->lpBinaryPathName)
  170. HeapFree(GetProcessHeap(), 0, old_cfg->lpBinaryPathName);
  171. if (old_cfg->lpLoadOrderGroup != new_cfg->lpLoadOrderGroup)
  172. HeapFree(GetProcessHeap(), 0, old_cfg->lpLoadOrderGroup);
  173. if (old_cfg->lpServiceStartName != new_cfg->lpServiceStartName)
  174. HeapFree(GetProcessHeap(), 0, old_cfg->lpServiceStartName);
  175. if (old_cfg->lpDisplayName != new_cfg->lpDisplayName)
  176. HeapFree(GetProcessHeap(), 0, old_cfg->lpDisplayName);
  177. if (old->dependOnServices != new->dependOnServices)
  178. HeapFree(GetProcessHeap(), 0, old->dependOnServices);
  179. if (old->dependOnGroups != new->dependOnGroups)
  180. HeapFree(GetProcessHeap(), 0, old->dependOnGroups);
  181. }
  182. /* Check if the given handle is of the required type and allows the requested access. */
  183. static DWORD validate_context_handle(SC_RPC_HANDLE handle, DWORD type, DWORD needed_access, struct sc_handle **out_hdr)
  184. {
  185. struct sc_handle *hdr = handle;
  186. if (type != SC_HTYPE_DONT_CARE && hdr->type != type)
  187. {
  188. WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr->type, type);
  189. return ERROR_INVALID_HANDLE;
  190. }
  191. if ((needed_access & hdr->access) != needed_access)
  192. {
  193. WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr->access, needed_access);
  194. return ERROR_ACCESS_DENIED;
  195. }
  196. *out_hdr = hdr;
  197. return ERROR_SUCCESS;
  198. }
  199. static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
  200. {
  201. struct sc_handle *hdr;
  202. DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
  203. if (err == ERROR_SUCCESS)
  204. *manager = (struct sc_manager_handle *)hdr;
  205. return err;
  206. }
  207. static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
  208. {
  209. struct sc_handle *hdr;
  210. DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
  211. if (err == ERROR_SUCCESS)
  212. *service = (struct sc_service_handle *)hdr;
  213. return err;
  214. }
  215. static DWORD validate_notify_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_notify_handle **notify)
  216. {
  217. struct sc_handle *hdr;
  218. DWORD err = validate_context_handle(handle, SC_HTYPE_NOTIFY, needed_access, &hdr);
  219. if (err == ERROR_SUCCESS)
  220. *notify = (struct sc_notify_handle *)hdr;
  221. return err;
  222. }
  223. DWORD __cdecl svcctl_OpenSCManagerW(
  224. MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
  225. LPCWSTR DatabaseName,
  226. DWORD dwAccessMask,
  227. SC_RPC_HANDLE *handle)
  228. {
  229. struct sc_manager_handle *manager;
  230. WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
  231. if (DatabaseName != NULL && DatabaseName[0])
  232. {
  233. if (lstrcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
  234. return ERROR_DATABASE_DOES_NOT_EXIST;
  235. if (lstrcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
  236. return ERROR_INVALID_NAME;
  237. }
  238. if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
  239. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  240. manager->hdr.type = SC_HTYPE_MANAGER;
  241. if (dwAccessMask & MAXIMUM_ALLOWED)
  242. dwAccessMask |= SC_MANAGER_ALL_ACCESS;
  243. manager->hdr.access = dwAccessMask;
  244. RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
  245. manager->db = active_database;
  246. *handle = &manager->hdr;
  247. return ERROR_SUCCESS;
  248. }
  249. static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
  250. {
  251. struct sc_handle *hdr = handle;
  252. switch (hdr->type)
  253. {
  254. case SC_HTYPE_MANAGER:
  255. {
  256. struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
  257. HeapFree(GetProcessHeap(), 0, manager);
  258. break;
  259. }
  260. case SC_HTYPE_SERVICE:
  261. {
  262. struct sc_service_handle *service = (struct sc_service_handle *)hdr;
  263. service_lock(service->service_entry);
  264. list_remove(&service->entry);
  265. if (service->notify)
  266. {
  267. SetEvent(service->notify->event);
  268. sc_notify_release(service->notify);
  269. }
  270. service_unlock(service->service_entry);
  271. release_service(service->service_entry);
  272. HeapFree(GetProcessHeap(), 0, service);
  273. break;
  274. }
  275. default:
  276. WINE_ERR("invalid handle type %d\n", hdr->type);
  277. RpcRaiseException(ERROR_INVALID_HANDLE);
  278. }
  279. }
  280. DWORD __cdecl svcctl_GetServiceDisplayNameW(
  281. SC_RPC_HANDLE hSCManager,
  282. LPCWSTR lpServiceName,
  283. WCHAR *lpBuffer,
  284. DWORD *cchBufSize)
  285. {
  286. struct sc_manager_handle *manager;
  287. struct service_entry *entry;
  288. DWORD err;
  289. WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), *cchBufSize);
  290. if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
  291. return err;
  292. scmdatabase_lock(manager->db);
  293. entry = scmdatabase_find_service(manager->db, lpServiceName);
  294. if (entry != NULL)
  295. {
  296. LPCWSTR name;
  297. int len;
  298. name = get_display_name(entry);
  299. len = lstrlenW(name);
  300. if (len <= *cchBufSize)
  301. {
  302. err = ERROR_SUCCESS;
  303. memcpy(lpBuffer, name, (len + 1)*sizeof(*name));
  304. }
  305. else
  306. err = ERROR_INSUFFICIENT_BUFFER;
  307. *cchBufSize = len;
  308. }
  309. else
  310. err = ERROR_SERVICE_DOES_NOT_EXIST;
  311. scmdatabase_unlock(manager->db);
  312. if (err != ERROR_SUCCESS)
  313. lpBuffer[0] = 0;
  314. return err;
  315. }
  316. DWORD __cdecl svcctl_GetServiceKeyNameW(
  317. SC_RPC_HANDLE hSCManager,
  318. LPCWSTR lpServiceDisplayName,
  319. WCHAR *lpBuffer,
  320. DWORD *cchBufSize)
  321. {
  322. struct service_entry *entry;
  323. struct sc_manager_handle *manager;
  324. DWORD err;
  325. WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), *cchBufSize);
  326. if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
  327. return err;
  328. scmdatabase_lock(manager->db);
  329. entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
  330. if (entry != NULL)
  331. {
  332. int len;
  333. len = lstrlenW(entry->name);
  334. if (len <= *cchBufSize)
  335. {
  336. err = ERROR_SUCCESS;
  337. memcpy(lpBuffer, entry->name, (len + 1)*sizeof(*entry->name));
  338. }
  339. else
  340. err = ERROR_INSUFFICIENT_BUFFER;
  341. *cchBufSize = len;
  342. }
  343. else
  344. err = ERROR_SERVICE_DOES_NOT_EXIST;
  345. scmdatabase_unlock(manager->db);
  346. if (err != ERROR_SUCCESS)
  347. lpBuffer[0] = 0;
  348. return err;
  349. }
  350. static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
  351. {
  352. struct sc_service_handle *service;
  353. if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
  354. {
  355. release_service(entry);
  356. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  357. }
  358. if (dwDesiredAccess & MAXIMUM_ALLOWED)
  359. dwDesiredAccess |= SERVICE_ALL_ACCESS;
  360. service->hdr.type = SC_HTYPE_SERVICE;
  361. service->hdr.access = dwDesiredAccess;
  362. service->notify = NULL;
  363. service->status_notified = FALSE;
  364. RtlMapGenericMask(&service->hdr.access, &g_svc_generic);
  365. service_lock(entry);
  366. service->service_entry = entry;
  367. list_add_tail(&entry->handles, &service->entry);
  368. service_unlock(entry);
  369. *phService = &service->hdr;
  370. return ERROR_SUCCESS;
  371. }
  372. DWORD __cdecl svcctl_OpenServiceW(
  373. SC_RPC_HANDLE hSCManager,
  374. LPCWSTR lpServiceName,
  375. DWORD dwDesiredAccess,
  376. SC_RPC_HANDLE *phService)
  377. {
  378. struct sc_manager_handle *manager;
  379. struct service_entry *entry;
  380. DWORD err;
  381. WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName), dwDesiredAccess);
  382. if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
  383. return err;
  384. if (!validate_service_name(lpServiceName))
  385. return ERROR_INVALID_NAME;
  386. scmdatabase_lock(manager->db);
  387. entry = grab_service(scmdatabase_find_service(manager->db, lpServiceName));
  388. scmdatabase_unlock(manager->db);
  389. if (entry == NULL)
  390. return ERROR_SERVICE_DOES_NOT_EXIST;
  391. return create_handle_for_service(entry, dwDesiredAccess, phService);
  392. }
  393. static DWORD parse_dependencies(const WCHAR *dependencies, struct service_entry *entry)
  394. {
  395. WCHAR *services = NULL, *groups, *s;
  396. DWORD len, len_services = 0, len_groups = 0;
  397. const WCHAR *ptr = dependencies;
  398. if (!dependencies || !dependencies[0])
  399. {
  400. entry->dependOnServices = NULL;
  401. entry->dependOnGroups = NULL;
  402. return ERROR_SUCCESS;
  403. }
  404. while (*ptr)
  405. {
  406. len = lstrlenW(ptr) + 1;
  407. if (ptr[0] == '+' && ptr[1])
  408. len_groups += len - 1;
  409. else
  410. len_services += len;
  411. ptr += len;
  412. }
  413. if (!len_services) entry->dependOnServices = NULL;
  414. else
  415. {
  416. services = HeapAlloc(GetProcessHeap(), 0, (len_services + 1) * sizeof(WCHAR));
  417. if (!services)
  418. return ERROR_OUTOFMEMORY;
  419. s = services;
  420. ptr = dependencies;
  421. while (*ptr)
  422. {
  423. len = lstrlenW(ptr) + 1;
  424. if (*ptr != '+')
  425. {
  426. lstrcpyW(s, ptr);
  427. s += len;
  428. }
  429. ptr += len;
  430. }
  431. *s = 0;
  432. entry->dependOnServices = services;
  433. }
  434. if (!len_groups) entry->dependOnGroups = NULL;
  435. else
  436. {
  437. groups = HeapAlloc(GetProcessHeap(), 0, (len_groups + 1) * sizeof(WCHAR));
  438. if (!groups)
  439. {
  440. HeapFree(GetProcessHeap(), 0, services);
  441. return ERROR_OUTOFMEMORY;
  442. }
  443. s = groups;
  444. ptr = dependencies;
  445. while (*ptr)
  446. {
  447. len = lstrlenW(ptr) + 1;
  448. if (ptr[0] == '+' && ptr[1])
  449. {
  450. lstrcpyW(s, ptr + 1);
  451. s += len - 1;
  452. }
  453. ptr += len;
  454. }
  455. *s = 0;
  456. entry->dependOnGroups = groups;
  457. }
  458. return ERROR_SUCCESS;
  459. }
  460. static DWORD create_serviceW(
  461. SC_RPC_HANDLE hSCManager,
  462. LPCWSTR lpServiceName,
  463. LPCWSTR lpDisplayName,
  464. DWORD dwDesiredAccess,
  465. DWORD dwServiceType,
  466. DWORD dwStartType,
  467. DWORD dwErrorControl,
  468. LPCWSTR lpBinaryPathName,
  469. LPCWSTR lpLoadOrderGroup,
  470. DWORD *lpdwTagId,
  471. const BYTE *lpDependencies,
  472. DWORD dwDependenciesSize,
  473. LPCWSTR lpServiceStartName,
  474. const BYTE *lpPassword,
  475. DWORD dwPasswordSize,
  476. SC_RPC_HANDLE *phService,
  477. BOOL is_wow64)
  478. {
  479. struct service_entry *entry, *found;
  480. struct sc_manager_handle *manager;
  481. DWORD err;
  482. WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
  483. if ((err = validate_scm_handle(hSCManager, SC_MANAGER_CREATE_SERVICE, &manager)) != ERROR_SUCCESS)
  484. return err;
  485. if (!validate_service_name(lpServiceName))
  486. return ERROR_INVALID_NAME;
  487. if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize) || !lpServiceName[0] || !lpBinaryPathName[0])
  488. return ERROR_INVALID_PARAMETER;
  489. if (lpPassword)
  490. WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
  491. err = service_create(lpServiceName, &entry);
  492. if (err != ERROR_SUCCESS)
  493. return err;
  494. err = parse_dependencies((LPCWSTR)lpDependencies, entry);
  495. if (err != ERROR_SUCCESS) {
  496. free_service_entry(entry);
  497. return err;
  498. }
  499. entry->is_wow64 = is_wow64;
  500. entry->config.dwServiceType = entry->status.dwServiceType = dwServiceType;
  501. entry->config.dwStartType = dwStartType;
  502. entry->config.dwErrorControl = dwErrorControl;
  503. entry->config.lpBinaryPathName = strdupW(lpBinaryPathName);
  504. entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
  505. entry->config.lpServiceStartName = strdupW(lpServiceStartName);
  506. entry->config.lpDisplayName = strdupW(lpDisplayName);
  507. if (lpdwTagId) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
  508. entry->config.dwTagId = *lpdwTagId;
  509. else
  510. entry->config.dwTagId = 0;
  511. /* other fields NULL*/
  512. if (!validate_service_config(entry))
  513. {
  514. WINE_ERR("Invalid data while trying to create service\n");
  515. free_service_entry(entry);
  516. return ERROR_INVALID_PARAMETER;
  517. }
  518. scmdatabase_lock(manager->db);
  519. if ((found = scmdatabase_find_service(manager->db, lpServiceName)))
  520. {
  521. err = is_marked_for_delete(found) ? ERROR_SERVICE_MARKED_FOR_DELETE : ERROR_SERVICE_EXISTS;
  522. scmdatabase_unlock(manager->db);
  523. free_service_entry(entry);
  524. return err;
  525. }
  526. if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
  527. {
  528. scmdatabase_unlock(manager->db);
  529. free_service_entry(entry);
  530. return ERROR_DUPLICATE_SERVICE_NAME;
  531. }
  532. err = scmdatabase_add_service(manager->db, entry);
  533. if (err != ERROR_SUCCESS)
  534. {
  535. scmdatabase_unlock(manager->db);
  536. free_service_entry(entry);
  537. return err;
  538. }
  539. scmdatabase_unlock(manager->db);
  540. return create_handle_for_service(entry, dwDesiredAccess, phService);
  541. }
  542. DWORD __cdecl svcctl_CreateServiceW(
  543. SC_RPC_HANDLE hSCManager,
  544. LPCWSTR lpServiceName,
  545. LPCWSTR lpDisplayName,
  546. DWORD dwDesiredAccess,
  547. DWORD dwServiceType,
  548. DWORD dwStartType,
  549. DWORD dwErrorControl,
  550. LPCWSTR lpBinaryPathName,
  551. LPCWSTR lpLoadOrderGroup,
  552. DWORD *lpdwTagId,
  553. const BYTE *lpDependencies,
  554. DWORD dwDependenciesSize,
  555. LPCWSTR lpServiceStartName,
  556. const BYTE *lpPassword,
  557. DWORD dwPasswordSize,
  558. SC_RPC_HANDLE *phService)
  559. {
  560. WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
  561. return create_serviceW(hSCManager, lpServiceName, lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType,
  562. dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, lpDependencies, dwDependenciesSize, lpServiceStartName,
  563. lpPassword, dwPasswordSize, phService, FALSE);
  564. }
  565. DWORD __cdecl svcctl_DeleteService(
  566. SC_RPC_HANDLE hService)
  567. {
  568. struct sc_service_handle *service;
  569. DWORD err;
  570. if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
  571. return err;
  572. service_lock(service->service_entry);
  573. if (!is_marked_for_delete(service->service_entry))
  574. err = mark_for_delete(service->service_entry);
  575. else
  576. err = ERROR_SERVICE_MARKED_FOR_DELETE;
  577. service_unlock(service->service_entry);
  578. return err;
  579. }
  580. DWORD __cdecl svcctl_QueryServiceConfigW(
  581. SC_RPC_HANDLE hService,
  582. QUERY_SERVICE_CONFIGW *config,
  583. DWORD buf_size,
  584. DWORD *needed_size)
  585. {
  586. struct sc_service_handle *service;
  587. DWORD err;
  588. WINE_TRACE("(%p)\n", config);
  589. if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
  590. return err;
  591. service_lock(service->service_entry);
  592. config->dwServiceType = service->service_entry->config.dwServiceType;
  593. config->dwStartType = service->service_entry->config.dwStartType;
  594. config->dwErrorControl = service->service_entry->config.dwErrorControl;
  595. config->lpBinaryPathName = strdupW(service->service_entry->config.lpBinaryPathName);
  596. config->lpLoadOrderGroup = strdupW(service->service_entry->config.lpLoadOrderGroup);
  597. config->dwTagId = service->service_entry->config.dwTagId;
  598. config->lpDependencies = NULL; /* TODO */
  599. config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
  600. config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
  601. service_unlock(service->service_entry);
  602. return ERROR_SUCCESS;
  603. }
  604. DWORD __cdecl svcctl_ChangeServiceConfigW(
  605. SC_RPC_HANDLE hService,
  606. DWORD dwServiceType,
  607. DWORD dwStartType,
  608. DWORD dwErrorControl,
  609. LPCWSTR lpBinaryPathName,
  610. LPCWSTR lpLoadOrderGroup,
  611. DWORD *lpdwTagId,
  612. const BYTE *lpDependencies,
  613. DWORD dwDependenciesSize,
  614. LPCWSTR lpServiceStartName,
  615. const BYTE *lpPassword,
  616. DWORD dwPasswordSize,
  617. LPCWSTR lpDisplayName)
  618. {
  619. struct service_entry new_entry, *entry;
  620. struct sc_service_handle *service;
  621. DWORD err;
  622. WINE_TRACE("\n");
  623. if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
  624. return err;
  625. if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
  626. return ERROR_INVALID_PARAMETER;
  627. /* first check if the new configuration is correct */
  628. service_lock(service->service_entry);
  629. if (is_marked_for_delete(service->service_entry))
  630. {
  631. service_unlock(service->service_entry);
  632. return ERROR_SERVICE_MARKED_FOR_DELETE;
  633. }
  634. if (lpDisplayName != NULL &&
  635. (entry = scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName)) &&
  636. (entry != service->service_entry))
  637. {
  638. service_unlock(service->service_entry);
  639. return ERROR_DUPLICATE_SERVICE_NAME;
  640. }
  641. new_entry = *service->service_entry;
  642. if (dwServiceType != SERVICE_NO_CHANGE)
  643. new_entry.config.dwServiceType = dwServiceType;
  644. if (dwStartType != SERVICE_NO_CHANGE)
  645. new_entry.config.dwStartType = dwStartType;
  646. if (dwErrorControl != SERVICE_NO_CHANGE)
  647. new_entry.config.dwErrorControl = dwErrorControl;
  648. if (lpBinaryPathName != NULL)
  649. new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
  650. if (lpLoadOrderGroup != NULL)
  651. new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
  652. if (lpdwTagId != NULL)
  653. WINE_FIXME("Changing tag id not supported\n");
  654. if (lpServiceStartName != NULL)
  655. new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
  656. if (lpPassword != NULL)
  657. WINE_FIXME("Setting password not supported\n");
  658. if (lpDisplayName != NULL)
  659. new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
  660. err = parse_dependencies((LPCWSTR)lpDependencies, &new_entry);
  661. if (err != ERROR_SUCCESS)
  662. {
  663. service_unlock(service->service_entry);
  664. return err;
  665. }
  666. if (!validate_service_config(&new_entry))
  667. {
  668. WINE_ERR("The configuration after the change wouldn't be valid\n");
  669. service_unlock(service->service_entry);
  670. return ERROR_INVALID_PARAMETER;
  671. }
  672. /* configuration OK. The strings needs to be duplicated */
  673. if (lpBinaryPathName != NULL)
  674. new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
  675. if (lpLoadOrderGroup != NULL)
  676. new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
  677. if (lpServiceStartName != NULL)
  678. new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
  679. if (lpDisplayName != NULL)
  680. new_entry.config.lpDisplayName = strdupW(lpDisplayName);
  681. /* try to save to Registry, commit or rollback depending on success */
  682. err = save_service_config(&new_entry);
  683. if (ERROR_SUCCESS == err)
  684. {
  685. free_service_strings(service->service_entry, &new_entry);
  686. *service->service_entry = new_entry;
  687. }
  688. else free_service_strings(&new_entry, service->service_entry);
  689. service_unlock(service->service_entry);
  690. return err;
  691. }
  692. static void fill_status_process(SERVICE_STATUS_PROCESS *status, struct service_entry *service)
  693. {
  694. struct process_entry *process = service->process;
  695. memcpy(status, &service->status, sizeof(service->status));
  696. status->dwProcessId = 0;
  697. if (process && !(service->status.dwServiceType & SERVICE_DRIVER))
  698. status->dwProcessId = process->process_id;
  699. status->dwServiceFlags = 0;
  700. }
  701. static void fill_notify(struct sc_notify_handle *notify, struct service_entry *service)
  702. {
  703. SC_RPC_NOTIFY_PARAMS_LIST *list;
  704. SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
  705. list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  706. sizeof(SC_RPC_NOTIFY_PARAMS_LIST) + sizeof(SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2));
  707. if (!list)
  708. return;
  709. cparams = (SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *)(list + 1);
  710. cparams->dwNotifyMask = notify->notify_mask;
  711. fill_status_process(&cparams->ServiceStatus, service);
  712. cparams->dwNotificationStatus = ERROR_SUCCESS;
  713. cparams->dwNotificationTriggered = 1 << (cparams->ServiceStatus.dwCurrentState - SERVICE_STOPPED);
  714. cparams->pszServiceNames = NULL;
  715. list->cElements = 1;
  716. list->NotifyParamsArray[0].dwInfoLevel = 2;
  717. list->NotifyParamsArray[0].params = cparams;
  718. InterlockedExchangePointer((void**)&notify->params_list, list);
  719. SetEvent(notify->event);
  720. }
  721. DWORD __cdecl svcctl_SetServiceStatus(SC_RPC_HANDLE handle, SERVICE_STATUS *status)
  722. {
  723. struct sc_service_handle *service, *service_handle;
  724. struct process_entry *process;
  725. DWORD err, mask;
  726. WINE_TRACE("(%p, %p)\n", handle, status);
  727. if ((err = validate_service_handle(handle, SERVICE_SET_STATUS, &service)) != 0)
  728. return err;
  729. service_lock(service->service_entry);
  730. /* FIXME: be a bit more discriminant about what parts of the status we set
  731. * and check that fields are valid */
  732. service->service_entry->status.dwCurrentState = status->dwCurrentState;
  733. service->service_entry->status.dwControlsAccepted = status->dwControlsAccepted;
  734. service->service_entry->status.dwWin32ExitCode = status->dwWin32ExitCode;
  735. service->service_entry->status.dwServiceSpecificExitCode = status->dwServiceSpecificExitCode;
  736. service->service_entry->status.dwCheckPoint = status->dwCheckPoint;
  737. service->service_entry->status.dwWaitHint = status->dwWaitHint;
  738. SetEvent(service->service_entry->status_changed_event);
  739. if ((process = service->service_entry->process) &&
  740. status->dwCurrentState == SERVICE_STOPPED)
  741. {
  742. service->service_entry->process = NULL;
  743. if (!--process->use_count)
  744. terminate_after_timeout(process, service_kill_timeout);
  745. if (service->service_entry->shared_process && process->use_count <= 1)
  746. shutdown_shared_process(process);
  747. release_process(process);
  748. }
  749. mask = 1 << (service->service_entry->status.dwCurrentState - SERVICE_STOPPED);
  750. LIST_FOR_EACH_ENTRY(service_handle, &service->service_entry->handles, struct sc_service_handle, entry)
  751. {
  752. struct sc_notify_handle *notify = service_handle->notify;
  753. if (notify && (notify->notify_mask & mask))
  754. {
  755. fill_notify(notify, service->service_entry);
  756. sc_notify_release(notify);
  757. service_handle->notify = NULL;
  758. service_handle->status_notified = TRUE;
  759. }
  760. else
  761. service_handle->status_notified = FALSE;
  762. }
  763. service_unlock(service->service_entry);
  764. return ERROR_SUCCESS;
  765. }
  766. DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, SC_RPC_CONFIG_INFOW config )
  767. {
  768. struct sc_service_handle *service;
  769. DWORD err;
  770. if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
  771. return err;
  772. switch (config.dwInfoLevel)
  773. {
  774. case SERVICE_CONFIG_DESCRIPTION:
  775. {
  776. WCHAR *descr = NULL;
  777. if (!config.descr->lpDescription)
  778. break;
  779. if (config.descr->lpDescription[0])
  780. {
  781. if (!(descr = strdupW( config.descr->lpDescription )))
  782. return ERROR_NOT_ENOUGH_MEMORY;
  783. }
  784. WINE_TRACE( "changing service %p descr to %s\n", service, wine_dbgstr_w(descr) );
  785. service_lock( service->service_entry );
  786. HeapFree( GetProcessHeap(), 0, service->service_entry->description );
  787. service->service_entry->description = descr;
  788. save_service_config( service->service_entry );
  789. service_unlock( service->service_entry );
  790. }
  791. break;
  792. case SERVICE_CONFIG_FAILURE_ACTIONS:
  793. WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
  794. config.actions->dwResetPeriod,
  795. wine_dbgstr_w(config.actions->lpRebootMsg),
  796. wine_dbgstr_w(config.actions->lpCommand) );
  797. break;
  798. case SERVICE_CONFIG_PRESHUTDOWN_INFO:
  799. WINE_TRACE( "changing service %p preshutdown timeout to %d\n",
  800. service, config.preshutdown->dwPreshutdownTimeout );
  801. service_lock( service->service_entry );
  802. service->service_entry->preshutdown_timeout = config.preshutdown->dwPreshutdownTimeout;
  803. save_service_config( service->service_entry );
  804. service_unlock( service->service_entry );
  805. break;
  806. default:
  807. WINE_FIXME("level %u not implemented\n", config.dwInfoLevel);
  808. err = ERROR_INVALID_LEVEL;
  809. break;
  810. }
  811. return err;
  812. }
  813. DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
  814. BYTE *buffer, DWORD size, LPDWORD needed )
  815. {
  816. struct sc_service_handle *service;
  817. DWORD err;
  818. memset(buffer, 0, size);
  819. if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
  820. return err;
  821. switch (level)
  822. {
  823. case SERVICE_CONFIG_DESCRIPTION:
  824. {
  825. struct service_description *desc = (struct service_description *)buffer;
  826. DWORD total_size = sizeof(*desc);
  827. service_lock(service->service_entry);
  828. if (service->service_entry->description)
  829. total_size += lstrlenW(service->service_entry->description) * sizeof(WCHAR);
  830. *needed = total_size;
  831. if (size >= total_size)
  832. {
  833. if (service->service_entry->description)
  834. {
  835. lstrcpyW( desc->description, service->service_entry->description );
  836. desc->size = total_size - FIELD_OFFSET(struct service_description, description);
  837. }
  838. else
  839. {
  840. desc->description[0] = 0;
  841. desc->size = 0;
  842. }
  843. }
  844. else err = ERROR_INSUFFICIENT_BUFFER;
  845. service_unlock(service->service_entry);
  846. }
  847. break;
  848. case SERVICE_CONFIG_PRESHUTDOWN_INFO:
  849. service_lock(service->service_entry);
  850. *needed = sizeof(SERVICE_PRESHUTDOWN_INFO);
  851. if (size >= *needed)
  852. ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout =
  853. service->service_entry->preshutdown_timeout;
  854. else err = ERROR_INSUFFICIENT_BUFFER;
  855. service_unlock(service->service_entry);
  856. break;
  857. default:
  858. WINE_FIXME("level %u not implemented\n", level);
  859. err = ERROR_INVALID_LEVEL;
  860. break;
  861. }
  862. return err;
  863. }
  864. DWORD __cdecl svcctl_QueryServiceStatusEx(
  865. SC_RPC_HANDLE hService,
  866. SC_STATUS_TYPE InfoLevel,
  867. BYTE *lpBuffer,
  868. DWORD cbBufSize,
  869. LPDWORD pcbBytesNeeded)
  870. {
  871. struct sc_service_handle *service;
  872. DWORD err;
  873. LPSERVICE_STATUS_PROCESS pSvcStatusData;
  874. memset(lpBuffer, 0, cbBufSize);
  875. if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
  876. return err;
  877. if (InfoLevel != SC_STATUS_PROCESS_INFO)
  878. return ERROR_INVALID_LEVEL;
  879. pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
  880. if (pSvcStatusData == NULL)
  881. return ERROR_INVALID_PARAMETER;
  882. if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
  883. {
  884. if( pcbBytesNeeded != NULL)
  885. *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
  886. return ERROR_INSUFFICIENT_BUFFER;
  887. }
  888. service_lock(service->service_entry);
  889. fill_status_process(pSvcStatusData, service->service_entry);
  890. service_unlock(service->service_entry);
  891. return ERROR_SUCCESS;
  892. }
  893. /******************************************************************************
  894. * service_accepts_control
  895. */
  896. static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
  897. {
  898. DWORD a = service->status.dwControlsAccepted;
  899. if (dwControl >= 128 && dwControl <= 255)
  900. return TRUE;
  901. switch (dwControl)
  902. {
  903. case SERVICE_CONTROL_INTERROGATE:
  904. return TRUE;
  905. case SERVICE_CONTROL_STOP:
  906. if (a&SERVICE_ACCEPT_STOP)
  907. return TRUE;
  908. break;
  909. case SERVICE_CONTROL_SHUTDOWN:
  910. if (a&SERVICE_ACCEPT_SHUTDOWN)
  911. return TRUE;
  912. break;
  913. case SERVICE_CONTROL_PAUSE:
  914. case SERVICE_CONTROL_CONTINUE:
  915. if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
  916. return TRUE;
  917. break;
  918. case SERVICE_CONTROL_PARAMCHANGE:
  919. if (a&SERVICE_ACCEPT_PARAMCHANGE)
  920. return TRUE;
  921. break;
  922. case SERVICE_CONTROL_NETBINDADD:
  923. case SERVICE_CONTROL_NETBINDREMOVE:
  924. case SERVICE_CONTROL_NETBINDENABLE:
  925. case SERVICE_CONTROL_NETBINDDISABLE:
  926. if (a&SERVICE_ACCEPT_NETBINDCHANGE)
  927. return TRUE;
  928. case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
  929. if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
  930. return TRUE;
  931. break;
  932. case SERVICE_CONTROL_POWEREVENT:
  933. if (a&SERVICE_ACCEPT_POWEREVENT)
  934. return TRUE;
  935. break;
  936. case SERVICE_CONTROL_SESSIONCHANGE:
  937. if (a&SERVICE_ACCEPT_SESSIONCHANGE)
  938. return TRUE;
  939. break;
  940. }
  941. return FALSE;
  942. }
  943. /******************************************************************************
  944. * process_send_command
  945. */
  946. static BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
  947. {
  948. OVERLAPPED overlapped;
  949. DWORD count, ret;
  950. BOOL r;
  951. overlapped.u.s.Offset = 0;
  952. overlapped.u.s.OffsetHigh = 0;
  953. overlapped.hEvent = process->overlapped_event;
  954. r = WriteFile(process->control_pipe, data, size, &count, &overlapped);
  955. if (!r && GetLastError() == ERROR_IO_PENDING)
  956. {
  957. ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
  958. if (ret == WAIT_TIMEOUT)
  959. {
  960. WINE_ERR("sending command timed out\n");
  961. *result = ERROR_SERVICE_REQUEST_TIMEOUT;
  962. return FALSE;
  963. }
  964. r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
  965. }
  966. if (!r || count != size)
  967. {
  968. WINE_ERR("service protocol error - failed to write pipe!\n");
  969. *result = (!r ? GetLastError() : ERROR_WRITE_FAULT);
  970. return FALSE;
  971. }
  972. r = ReadFile(process->control_pipe, result, sizeof *result, &count, &overlapped);
  973. if (!r && GetLastError() == ERROR_IO_PENDING)
  974. {
  975. ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
  976. if (ret == WAIT_TIMEOUT)
  977. {
  978. WINE_ERR("receiving command result timed out\n");
  979. *result = ERROR_SERVICE_REQUEST_TIMEOUT;
  980. return FALSE;
  981. }
  982. r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
  983. }
  984. if (!r || count != sizeof *result)
  985. {
  986. WINE_ERR("service protocol error - failed to read pipe "
  987. "r = %d count = %d!\n", r, count);
  988. *result = (!r ? GetLastError() : ERROR_READ_FAULT);
  989. return FALSE;
  990. }
  991. return TRUE;
  992. }
  993. /******************************************************************************
  994. * process_send_control
  995. */
  996. BOOL process_send_control(struct process_entry *process, BOOL shared_process, const WCHAR *name,
  997. DWORD control, const BYTE *data, DWORD data_size, DWORD *result)
  998. {
  999. service_start_info *ssi;
  1000. DWORD len;
  1001. BOOL r;
  1002. if (shared_process)
  1003. {
  1004. control |= SERVICE_CONTROL_FORWARD_FLAG;
  1005. data = (BYTE *)name;
  1006. data_size = (lstrlenW(name) + 1) * sizeof(WCHAR);
  1007. name = emptyW;
  1008. }
  1009. /* calculate how much space we need to send the startup info */
  1010. len = (lstrlenW(name) + 1) * sizeof(WCHAR) + data_size;
  1011. ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
  1012. ssi->magic = SERVICE_PROTOCOL_MAGIC;
  1013. ssi->control = control;
  1014. ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
  1015. ssi->name_size = lstrlenW(name) + 1;
  1016. lstrcpyW((WCHAR *)ssi->data, name);
  1017. if (data_size) memcpy(&ssi->data[ssi->name_size * sizeof(WCHAR)], data, data_size);
  1018. r = process_send_command(process, ssi, ssi->total_size, result);
  1019. HeapFree( GetProcessHeap(), 0, ssi );
  1020. return r;
  1021. }
  1022. DWORD __cdecl svcctl_StartServiceW(
  1023. SC_RPC_HANDLE hService,
  1024. DWORD dwNumServiceArgs,
  1025. LPCWSTR *lpServiceArgVectors)
  1026. {
  1027. struct sc_service_handle *service;
  1028. DWORD err;
  1029. WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
  1030. if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
  1031. return err;
  1032. if (service->service_entry->config.dwStartType == SERVICE_DISABLED)
  1033. return ERROR_SERVICE_DISABLED;
  1034. if (!scmdatabase_lock_startup(service->service_entry->db, 3000))
  1035. return ERROR_SERVICE_DATABASE_LOCKED;
  1036. err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
  1037. scmdatabase_unlock_startup(service->service_entry->db);
  1038. return err;
  1039. }
  1040. DWORD __cdecl svcctl_ControlService(
  1041. SC_RPC_HANDLE hService,
  1042. DWORD dwControl,
  1043. SERVICE_STATUS *lpServiceStatus)
  1044. {
  1045. DWORD access_required;
  1046. struct sc_service_handle *service;
  1047. struct process_entry *process;
  1048. BOOL shared_process;
  1049. DWORD result;
  1050. WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
  1051. switch (dwControl)
  1052. {
  1053. case SERVICE_CONTROL_CONTINUE:
  1054. case SERVICE_CONTROL_NETBINDADD:
  1055. case SERVICE_CONTROL_NETBINDDISABLE:
  1056. case SERVICE_CONTROL_NETBINDENABLE:
  1057. case SERVICE_CONTROL_NETBINDREMOVE:
  1058. case SERVICE_CONTROL_PARAMCHANGE:
  1059. case SERVICE_CONTROL_PAUSE:
  1060. access_required = SERVICE_PAUSE_CONTINUE;
  1061. break;
  1062. case SERVICE_CONTROL_INTERROGATE:
  1063. access_required = SERVICE_INTERROGATE;
  1064. break;
  1065. case SERVICE_CONTROL_STOP:
  1066. access_required = SERVICE_STOP;
  1067. break;
  1068. default:
  1069. if (dwControl >= 128 && dwControl <= 255)
  1070. access_required = SERVICE_USER_DEFINED_CONTROL;
  1071. else
  1072. return ERROR_INVALID_PARAMETER;
  1073. }
  1074. if ((result = validate_service_handle(hService, access_required, &service)) != 0)
  1075. return result;
  1076. service_lock(service->service_entry);
  1077. result = ERROR_SUCCESS;
  1078. switch (service->service_entry->status.dwCurrentState)
  1079. {
  1080. case SERVICE_STOPPED:
  1081. result = ERROR_SERVICE_NOT_ACTIVE;
  1082. break;
  1083. case SERVICE_START_PENDING:
  1084. if (dwControl==SERVICE_CONTROL_STOP)
  1085. break;
  1086. /* fall through */
  1087. case SERVICE_STOP_PENDING:
  1088. result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
  1089. break;
  1090. }
  1091. if (result == ERROR_SUCCESS && service->service_entry->force_shutdown)
  1092. {
  1093. result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
  1094. if ((process = service->service_entry->process))
  1095. {
  1096. service->service_entry->process = NULL;
  1097. if (!--process->use_count) process_terminate(process);
  1098. release_process(process);
  1099. }
  1100. }
  1101. if (result != ERROR_SUCCESS)
  1102. {
  1103. if (lpServiceStatus) *lpServiceStatus = service->service_entry->status;
  1104. service_unlock(service->service_entry);
  1105. return result;
  1106. }
  1107. if (!service_accepts_control(service->service_entry, dwControl))
  1108. {
  1109. service_unlock(service->service_entry);
  1110. return ERROR_INVALID_SERVICE_CONTROL;
  1111. }
  1112. /* Remember that we tried to shutdown this service. When the service is
  1113. * still running on the second invocation, it will be forcefully killed. */
  1114. if (dwControl == SERVICE_CONTROL_STOP)
  1115. service->service_entry->force_shutdown = TRUE;
  1116. /* Hold a reference to the process while sending the command. */
  1117. process = grab_process(service->service_entry->process);
  1118. shared_process = service->service_entry->shared_process;
  1119. service_unlock(service->service_entry);
  1120. if (!process)
  1121. return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
  1122. result = WaitForSingleObject(process->control_mutex, 30000);
  1123. if (result != WAIT_OBJECT_0)
  1124. {
  1125. release_process(process);
  1126. return ERROR_SERVICE_REQUEST_TIMEOUT;
  1127. }
  1128. if (process_send_control(process, shared_process, service->service_entry->name,
  1129. dwControl, NULL, 0, &result))
  1130. result = ERROR_SUCCESS;
  1131. if (lpServiceStatus)
  1132. {
  1133. service_lock(service->service_entry);
  1134. *lpServiceStatus = service->service_entry->status;
  1135. service_unlock(service->service_entry);
  1136. }
  1137. ReleaseMutex(process->control_mutex);
  1138. release_process(process);
  1139. return result;
  1140. }
  1141. DWORD __cdecl svcctl_CloseServiceHandle(
  1142. SC_RPC_HANDLE *handle)
  1143. {
  1144. WINE_TRACE("(&%p)\n", *handle);
  1145. SC_RPC_HANDLE_destroy(*handle);
  1146. *handle = NULL;
  1147. return ERROR_SUCCESS;
  1148. }
  1149. void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
  1150. {
  1151. }
  1152. DWORD __cdecl svcctl_LockServiceDatabase(SC_RPC_HANDLE manager, SC_RPC_LOCK *lock)
  1153. {
  1154. TRACE("(%p, %p)\n", manager, lock);
  1155. *lock = (SC_RPC_LOCK)0xdeadbeef;
  1156. return ERROR_SUCCESS;
  1157. }
  1158. DWORD __cdecl svcctl_UnlockServiceDatabase(SC_RPC_LOCK *lock)
  1159. {
  1160. TRACE("(&%p)\n", *lock);
  1161. *lock = NULL;
  1162. return ERROR_SUCCESS;
  1163. }
  1164. static BOOL map_state(DWORD state, DWORD mask)
  1165. {
  1166. switch (state)
  1167. {
  1168. case SERVICE_START_PENDING:
  1169. case SERVICE_STOP_PENDING:
  1170. case SERVICE_RUNNING:
  1171. case SERVICE_CONTINUE_PENDING:
  1172. case SERVICE_PAUSE_PENDING:
  1173. case SERVICE_PAUSED:
  1174. if (SERVICE_ACTIVE & mask) return TRUE;
  1175. break;
  1176. case SERVICE_STOPPED:
  1177. if (SERVICE_INACTIVE & mask) return TRUE;
  1178. break;
  1179. default:
  1180. WINE_ERR("unknown state %u\n", state);
  1181. break;
  1182. }
  1183. return FALSE;
  1184. }
  1185. DWORD __cdecl svcctl_EnumServicesStatusW(
  1186. SC_RPC_HANDLE hmngr,
  1187. DWORD type,
  1188. DWORD state,
  1189. BYTE *buffer,
  1190. DWORD size,
  1191. LPDWORD needed,
  1192. LPDWORD returned,
  1193. LPDWORD resume)
  1194. {
  1195. DWORD err, sz, total_size, num_services, offset;
  1196. struct sc_manager_handle *manager;
  1197. struct service_entry *service;
  1198. struct enum_service_status *s;
  1199. WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned, resume);
  1200. if (!type || !state)
  1201. return ERROR_INVALID_PARAMETER;
  1202. if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
  1203. return err;
  1204. if (resume)
  1205. WINE_FIXME("resume index not supported\n");
  1206. scmdatabase_lock(manager->db);
  1207. total_size = num_services = 0;
  1208. LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
  1209. {
  1210. if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
  1211. {
  1212. total_size += sizeof(*s);
  1213. total_size += (lstrlenW(service->name) + 1) * sizeof(WCHAR);
  1214. if (service->config.lpDisplayName)
  1215. {
  1216. total_size += (lstrlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
  1217. }
  1218. num_services++;
  1219. }
  1220. }
  1221. *returned = 0;
  1222. *needed = total_size;
  1223. if (total_size > size)
  1224. {
  1225. scmdatabase_unlock(manager->db);
  1226. return ERROR_MORE_DATA;
  1227. }
  1228. s = (struct enum_service_status *)buffer;
  1229. offset = num_services * sizeof(struct enum_service_status);
  1230. LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
  1231. {
  1232. if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
  1233. {
  1234. sz = (lstrlenW(service->name) + 1) * sizeof(WCHAR);
  1235. memcpy(buffer + offset, service->name, sz);
  1236. s->service_name = offset;
  1237. offset += sz;
  1238. if (!service->config.lpDisplayName) s->display_name = 0;
  1239. else
  1240. {
  1241. sz = (lstrlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
  1242. memcpy(buffer + offset, service->config.lpDisplayName, sz);
  1243. s->display_name = offset;
  1244. offset += sz;
  1245. }
  1246. s->service_status = service->status;
  1247. s++;
  1248. }
  1249. }
  1250. *returned = num_services;
  1251. *needed = 0;
  1252. scmdatabase_unlock(manager->db);
  1253. return ERROR_SUCCESS;
  1254. }
  1255. static struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
  1256. {
  1257. struct service_entry *service;
  1258. LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
  1259. {
  1260. if (service->config.lpLoadOrderGroup && !wcsicmp(group, service->config.lpLoadOrderGroup))
  1261. return service;
  1262. }
  1263. return NULL;
  1264. }
  1265. static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
  1266. {
  1267. if (!g2) return TRUE;
  1268. if (!g2[0] && (!g1 || !g1[0])) return TRUE;
  1269. if (g1 && !lstrcmpW(g1, g2)) return TRUE;
  1270. return FALSE;
  1271. }
  1272. DWORD __cdecl svcctl_EnumServicesStatusExA(
  1273. SC_RPC_HANDLE scmanager,
  1274. SC_ENUM_TYPE info_level,
  1275. DWORD service_type,
  1276. DWORD service_state,
  1277. BYTE *buffer,
  1278. DWORD buf_size,
  1279. DWORD *needed_size,
  1280. DWORD *services_count,
  1281. DWORD *resume_index,
  1282. LPCSTR groupname)
  1283. {
  1284. WINE_FIXME("\n");
  1285. return ERROR_CALL_NOT_IMPLEMENTED;
  1286. }
  1287. DWORD __cdecl svcctl_EnumServicesStatusExW(
  1288. SC_RPC_HANDLE hmngr,
  1289. SC_ENUM_TYPE info_level,
  1290. DWORD type,
  1291. DWORD state,
  1292. BYTE *buffer,
  1293. DWORD size,
  1294. LPDWORD needed,
  1295. LPDWORD returned,
  1296. DWORD *resume_handle,
  1297. LPCWSTR group)
  1298. {
  1299. DWORD err, sz, total_size, num_services;
  1300. DWORD_PTR offset;
  1301. struct sc_manager_handle *manager;
  1302. struct service_entry *service;
  1303. struct enum_service_status_process *s;
  1304. WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
  1305. needed, returned, wine_dbgstr_w(group));
  1306. if (resume_handle)
  1307. FIXME("resume handle not supported\n");
  1308. if (!type || !state)
  1309. return ERROR_INVALID_PARAMETER;
  1310. if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
  1311. return err;
  1312. scmdatabase_lock(manager->db);
  1313. if (group && !find_service_by_group(manager->db, group))
  1314. {
  1315. scmdatabase_unlock(manager->db);
  1316. return ERROR_SERVICE_DOES_NOT_EXIST;
  1317. }
  1318. total_size = num_services = 0;
  1319. LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
  1320. {
  1321. if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
  1322. && match_group(service->config.lpLoadOrderGroup, group))
  1323. {
  1324. total_size += sizeof(*s);
  1325. total_size += (lstrlenW(service->name) + 1) * sizeof(WCHAR);
  1326. if (service->config.lpDisplayName)
  1327. {
  1328. total_size += (lstrlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
  1329. }
  1330. num_services++;
  1331. }
  1332. }
  1333. *returned = 0;
  1334. *needed = total_size;
  1335. if (total_size > size)
  1336. {
  1337. scmdatabase_unlock(manager->db);
  1338. return ERROR_MORE_DATA;
  1339. }
  1340. s = (struct enum_service_status_process *)buffer;
  1341. offset = num_services * sizeof(*s);
  1342. LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
  1343. {
  1344. if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
  1345. && match_group(service->config.lpLoadOrderGroup, group))
  1346. {
  1347. sz = (lstrlenW(service->name) + 1) * sizeof(WCHAR);
  1348. memcpy(buffer + offset, service->name, sz);
  1349. s->service_name = offset;
  1350. offset += sz;
  1351. if (!service->config.lpDisplayName) s->display_name = 0;
  1352. else
  1353. {
  1354. sz = (lstrlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
  1355. memcpy(buffer + offset, service->config.lpDisplayName, sz);
  1356. s->display_name = offset;
  1357. offset += sz;
  1358. }
  1359. fill_status_process(&s->service_status_process, service);
  1360. s++;
  1361. }
  1362. }
  1363. *returned = num_services;
  1364. *needed = 0;
  1365. scmdatabase_unlock(manager->db);
  1366. return ERROR_SUCCESS;
  1367. }
  1368. DWORD __cdecl svcctl_unknown43(void)
  1369. {
  1370. WINE_FIXME("\n");
  1371. return ERROR_CALL_NOT_IMPLEMENTED;
  1372. }
  1373. DWORD __cdecl svcctl_CreateServiceWOW64A(
  1374. SC_RPC_HANDLE scmanager,
  1375. LPCSTR servicename,
  1376. LPCSTR displayname,
  1377. DWORD accessmask,
  1378. DWORD service_type,
  1379. DWORD start_type,
  1380. DWORD error_control,
  1381. LPCSTR imagepath,
  1382. LPCSTR loadordergroup,
  1383. DWORD *tagid,
  1384. const BYTE *dependencies,
  1385. DWORD depend_size,
  1386. LPCSTR start_name,
  1387. const BYTE *password,
  1388. DWORD password_size,
  1389. SC_RPC_HANDLE *service)
  1390. {
  1391. WINE_FIXME("\n");
  1392. return ERROR_CALL_NOT_IMPLEMENTED;
  1393. }
  1394. DWORD __cdecl svcctl_CreateServiceWOW64W(
  1395. SC_RPC_HANDLE scmanager,
  1396. LPCWSTR servicename,
  1397. LPCWSTR displayname,
  1398. DWORD accessmask,
  1399. DWORD service_type,
  1400. DWORD start_type,
  1401. DWORD error_control,
  1402. LPCWSTR imagepath,
  1403. LPCWSTR loadordergroup,
  1404. DWORD *tagid,
  1405. const BYTE *dependencies,
  1406. DWORD depend_size,
  1407. LPCWSTR start_name,
  1408. const BYTE *password,
  1409. DWORD password_size,
  1410. SC_RPC_HANDLE *service)
  1411. {
  1412. WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(servicename), wine_dbgstr_w(displayname), accessmask, wine_dbgstr_w(imagepath));
  1413. return create_serviceW(scmanager, servicename, displayname, accessmask, service_type, start_type, error_control, imagepath,
  1414. loadordergroup, tagid, dependencies, depend_size, start_name, password, password_size, service, TRUE);
  1415. }
  1416. DWORD __cdecl svcctl_unknown46(void)
  1417. {
  1418. WINE_FIXME("\n");
  1419. return ERROR_CALL_NOT_IMPLEMENTED;
  1420. }
  1421. DWORD __cdecl svcctl_NotifyServiceStatusChange(
  1422. SC_RPC_HANDLE handle,
  1423. SC_RPC_NOTIFY_PARAMS params,
  1424. GUID *clientprocessguid,
  1425. GUID *scmprocessguid,
  1426. BOOL *createremotequeue,
  1427. SC_NOTIFY_RPC_HANDLE *hNotify)
  1428. {
  1429. DWORD err, mask;
  1430. struct sc_manager_handle *manager = NULL;
  1431. struct sc_service_handle *service = NULL;
  1432. struct sc_notify_handle *notify;
  1433. struct sc_handle *hdr = handle;
  1434. WINE_TRACE("(%p, NotifyMask: 0x%x, %p, %p, %p, %p)\n", handle,
  1435. params.params->dwNotifyMask, clientprocessguid, scmprocessguid,
  1436. createremotequeue, hNotify);
  1437. switch (hdr->type)
  1438. {
  1439. case SC_HTYPE_SERVICE:
  1440. err = validate_service_handle(handle, SERVICE_QUERY_STATUS, &service);
  1441. break;
  1442. case SC_HTYPE_MANAGER:
  1443. err = validate_scm_handle(handle, SC_MANAGER_ENUMERATE_SERVICE, &manager);
  1444. break;
  1445. default:
  1446. err = ERROR_INVALID_HANDLE;
  1447. break;
  1448. }
  1449. if (err != ERROR_SUCCESS)
  1450. return err;
  1451. if (manager)
  1452. {
  1453. WARN("Need support for service creation/deletion notifications\n");
  1454. return ERROR_CALL_NOT_IMPLEMENTED;
  1455. }
  1456. notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*notify));
  1457. if (!notify)
  1458. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1459. notify->hdr.type = SC_HTYPE_NOTIFY;
  1460. notify->hdr.access = 0;
  1461. notify->event = CreateEventW(NULL, TRUE, FALSE, NULL);
  1462. notify->notify_mask = params.params->dwNotifyMask;
  1463. service_lock(service->service_entry);
  1464. if (service->notify)
  1465. {
  1466. service_unlock(service->service_entry);
  1467. sc_notify_release(notify);
  1468. return ERROR_ALREADY_REGISTERED;
  1469. }
  1470. mask = 1 << (service->service_entry->status.dwCurrentState - SERVICE_STOPPED);
  1471. if (!service->status_notified && (notify->notify_mask & mask))
  1472. {
  1473. fill_notify(notify, service->service_entry);
  1474. service->status_notified = TRUE;
  1475. }
  1476. else
  1477. {
  1478. sc_notify_retain(notify);
  1479. service->notify = notify;
  1480. }
  1481. sc_notify_retain(notify);
  1482. *hNotify = &notify->hdr;
  1483. service_unlock(service->service_entry);
  1484. return ERROR_SUCCESS;
  1485. }
  1486. DWORD __cdecl svcctl_GetNotifyResults(
  1487. SC_NOTIFY_RPC_HANDLE hNotify,
  1488. SC_RPC_NOTIFY_PARAMS_LIST **pList)
  1489. {
  1490. DWORD err;
  1491. struct sc_notify_handle *notify;
  1492. WINE_TRACE("(%p, %p)\n", hNotify, pList);
  1493. if (!pList)
  1494. return ERROR_INVALID_PARAMETER;
  1495. *pList = NULL;
  1496. if ((err = validate_notify_handle(hNotify, 0, &notify)) != 0)
  1497. return err;
  1498. sc_notify_retain(notify);
  1499. /* block until there is a result */
  1500. err = WaitForSingleObject(notify->event, INFINITE);
  1501. if (err != WAIT_OBJECT_0)
  1502. {
  1503. sc_notify_release(notify);
  1504. return err;
  1505. }
  1506. *pList = InterlockedExchangePointer((void**)&notify->params_list, NULL);
  1507. if (!*pList)
  1508. {
  1509. sc_notify_release(notify);
  1510. return ERROR_REQUEST_ABORTED;
  1511. }
  1512. sc_notify_release(notify);
  1513. return ERROR_SUCCESS;
  1514. }
  1515. DWORD __cdecl svcctl_CloseNotifyHandle(
  1516. SC_NOTIFY_RPC_HANDLE *hNotify,
  1517. BOOL *apc_fired)
  1518. {
  1519. struct sc_notify_handle *notify;
  1520. DWORD err;
  1521. WINE_TRACE("(%p, %p)\n", hNotify, apc_fired);
  1522. if ((err = validate_notify_handle(*hNotify, 0, &notify)) != 0)
  1523. return err;
  1524. sc_notify_release(notify);
  1525. return ERROR_SUCCESS;
  1526. }
  1527. DWORD __cdecl svcctl_ControlServiceExA(
  1528. SC_RPC_HANDLE service,
  1529. DWORD control,
  1530. DWORD info_level,
  1531. SC_RPC_SERVICE_CONTROL_IN_PARAMSA *in_params,
  1532. SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *out_params)
  1533. {
  1534. WINE_FIXME("\n");
  1535. return ERROR_CALL_NOT_IMPLEMENTED;
  1536. }
  1537. DWORD __cdecl svcctl_ControlServiceExW(
  1538. SC_RPC_HANDLE service,
  1539. DWORD control,
  1540. DWORD info_level,
  1541. SC_RPC_SERVICE_CONTROL_IN_PARAMSW *in_params,
  1542. SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *out_params)
  1543. {
  1544. WINE_FIXME("\n");
  1545. return ERROR_CALL_NOT_IMPLEMENTED;
  1546. }
  1547. DWORD __cdecl svcctl_unknown52(void)
  1548. {
  1549. WINE_FIXME("\n");
  1550. return ERROR_CALL_NOT_IMPLEMENTED;
  1551. }
  1552. DWORD __cdecl svcctl_unknown53(void)
  1553. {
  1554. WINE_FIXME("\n");
  1555. return ERROR_CALL_NOT_IMPLEMENTED;
  1556. }
  1557. DWORD __cdecl svcctl_unknown54(void)
  1558. {
  1559. WINE_FIXME("\n");
  1560. return ERROR_CALL_NOT_IMPLEMENTED;
  1561. }
  1562. DWORD __cdecl svcctl_unknown55(void)
  1563. {
  1564. WINE_FIXME("\n");
  1565. return ERROR_CALL_NOT_IMPLEMENTED;
  1566. }
  1567. DWORD __cdecl svcctl_QueryServiceConfigEx(
  1568. SC_RPC_HANDLE service,
  1569. DWORD info_level,
  1570. SC_RPC_CONFIG_INFOW *info)
  1571. {
  1572. WINE_FIXME("\n");
  1573. return ERROR_CALL_NOT_IMPLEMENTED;
  1574. }
  1575. DWORD __cdecl svcctl_QueryServiceObjectSecurity(
  1576. SC_RPC_HANDLE service,
  1577. SECURITY_INFORMATION info,
  1578. BYTE *descriptor,
  1579. DWORD buf_size,
  1580. DWORD *needed_size)
  1581. {
  1582. WINE_FIXME("\n");
  1583. return ERROR_CALL_NOT_IMPLEMENTED;
  1584. }
  1585. DWORD __cdecl svcctl_SetServiceObjectSecurity(
  1586. SC_RPC_HANDLE service,
  1587. SECURITY_INFORMATION info,
  1588. BYTE *descriptor,
  1589. DWORD buf_size)
  1590. {
  1591. WINE_FIXME("\n");
  1592. return ERROR_CALL_NOT_IMPLEMENTED;
  1593. }
  1594. DWORD __cdecl svcctl_QueryServiceStatus(
  1595. SC_RPC_HANDLE service,
  1596. SERVICE_STATUS *status)
  1597. {
  1598. WINE_FIXME("\n");
  1599. return ERROR_CALL_NOT_IMPLEMENTED;
  1600. }
  1601. DWORD __cdecl svcctl_NotifyBootConfigStatus(
  1602. SVCCTL_HANDLEW machinename,
  1603. DWORD boot_acceptable)
  1604. {
  1605. WINE_FIXME("\n");
  1606. return ERROR_CALL_NOT_IMPLEMENTED;
  1607. }
  1608. DWORD __cdecl svcctl_SCSetServiceBitsW(void)
  1609. {
  1610. WINE_FIXME("\n");
  1611. return ERROR_CALL_NOT_IMPLEMENTED;
  1612. }
  1613. DWORD __cdecl svcctl_EnumDependentServicesW(
  1614. SC_RPC_HANDLE service,
  1615. DWORD state,
  1616. BYTE *services,
  1617. DWORD buf_size,
  1618. DWORD *needed_size,
  1619. DWORD *services_ret)
  1620. {
  1621. WINE_FIXME("\n");
  1622. return ERROR_CALL_NOT_IMPLEMENTED;
  1623. }
  1624. DWORD __cdecl svcctl_QueryServiceLockStatusW(
  1625. SC_RPC_HANDLE scmanager,
  1626. QUERY_SERVICE_LOCK_STATUSW *status,
  1627. DWORD buf_size,
  1628. DWORD *needed_size)
  1629. {
  1630. WINE_FIXME("\n");
  1631. return ERROR_CALL_NOT_IMPLEMENTED;
  1632. }
  1633. DWORD __cdecl svcctl_SCSetServiceBitsA(void)
  1634. {
  1635. WINE_FIXME("\n");
  1636. return ERROR_CALL_NOT_IMPLEMENTED;
  1637. }
  1638. DWORD __cdecl svcctl_ChangeServiceConfigA(
  1639. SC_RPC_HANDLE service,
  1640. DWORD service_type,
  1641. DWORD start_type,
  1642. DWORD error_control,
  1643. LPSTR binarypath,
  1644. LPSTR loadordergroup,
  1645. DWORD *tagid,
  1646. BYTE *dependencies,
  1647. DWORD depend_size,
  1648. LPSTR startname,
  1649. BYTE *password,
  1650. DWORD password_size,
  1651. LPSTR displayname)
  1652. {
  1653. WINE_FIXME("\n");
  1654. return ERROR_CALL_NOT_IMPLEMENTED;
  1655. }
  1656. DWORD __cdecl svcctl_CreateServiceA(
  1657. SC_RPC_HANDLE scmanager,
  1658. LPCSTR servicename,
  1659. LPCSTR displayname,
  1660. DWORD desiredaccess,
  1661. DWORD service_type,
  1662. DWORD start_type,
  1663. DWORD error_control,
  1664. LPCSTR binarypath,
  1665. LPCSTR loadordergroup,
  1666. DWORD *tagid,
  1667. const BYTE *dependencies,
  1668. DWORD depend_size,
  1669. LPCSTR startname,
  1670. const BYTE *password,
  1671. DWORD password_size,
  1672. SC_RPC_HANDLE *service)
  1673. {
  1674. WINE_FIXME("\n");
  1675. return ERROR_CALL_NOT_IMPLEMENTED;
  1676. }
  1677. DWORD __cdecl svcctl_EnumDependentServicesA(
  1678. SC_RPC_HANDLE service,
  1679. DWORD state,
  1680. BYTE *services,
  1681. DWORD buf_size,
  1682. DWORD *needed_size,
  1683. DWORD *services_ret)
  1684. {
  1685. WINE_FIXME("\n");
  1686. return ERROR_CALL_NOT_IMPLEMENTED;
  1687. }
  1688. DWORD __cdecl svcctl_EnumServicesStatusA(
  1689. SC_RPC_HANDLE hmngr,
  1690. DWORD type,
  1691. DWORD state,
  1692. BYTE *buffer,
  1693. DWORD size,
  1694. DWORD *needed,
  1695. DWORD *returned,
  1696. DWORD *resume)
  1697. {
  1698. WINE_FIXME("\n");
  1699. return ERROR_CALL_NOT_IMPLEMENTED;
  1700. }
  1701. DWORD __cdecl svcctl_OpenSCManagerA(
  1702. MACHINE_HANDLEA MachineName,
  1703. LPCSTR DatabaseName,
  1704. DWORD dwAccessMask,
  1705. SC_RPC_HANDLE *handle)
  1706. {
  1707. WINE_FIXME("\n");
  1708. return ERROR_CALL_NOT_IMPLEMENTED;
  1709. }
  1710. DWORD __cdecl svcctl_OpenServiceA(
  1711. SC_RPC_HANDLE hSCManager,
  1712. LPCSTR lpServiceName,
  1713. DWORD dwDesiredAccess,
  1714. SC_RPC_HANDLE *phService)
  1715. {
  1716. WINE_FIXME("\n");
  1717. return ERROR_CALL_NOT_IMPLEMENTED;
  1718. }
  1719. DWORD __cdecl svcctl_QueryServiceConfigA(
  1720. SC_RPC_HANDLE hService,
  1721. QUERY_SERVICE_CONFIGA *config,
  1722. DWORD buf_size,
  1723. DWORD *needed_size)
  1724. {
  1725. WINE_FIXME("\n");
  1726. return ERROR_CALL_NOT_IMPLEMENTED;
  1727. }
  1728. DWORD __cdecl svcctl_QueryServiceLockStatusA(
  1729. SC_RPC_HANDLE scmanager,
  1730. QUERY_SERVICE_LOCK_STATUSA *status,
  1731. DWORD buf_size,
  1732. DWORD *needed_size)
  1733. {
  1734. WINE_FIXME("\n");
  1735. return ERROR_CALL_NOT_IMPLEMENTED;
  1736. }
  1737. DWORD __cdecl svcctl_StartServiceA(
  1738. SC_RPC_HANDLE service,
  1739. DWORD argc,
  1740. LPCSTR *args)
  1741. {
  1742. WINE_FIXME("\n");
  1743. return ERROR_CALL_NOT_IMPLEMENTED;
  1744. }
  1745. DWORD __cdecl svcctl_GetServiceDisplayNameA(
  1746. SC_RPC_HANDLE hSCManager,
  1747. LPCSTR servicename,
  1748. CHAR buffer[],
  1749. DWORD *buf_size)
  1750. {
  1751. WINE_FIXME("\n");
  1752. return ERROR_CALL_NOT_IMPLEMENTED;
  1753. }
  1754. DWORD __cdecl svcctl_GetServiceKeyNameA(
  1755. SC_RPC_HANDLE hSCManager,
  1756. LPCSTR servicename,
  1757. CHAR buffer[],
  1758. DWORD *buf_size)
  1759. {
  1760. WINE_FIXME("\n");
  1761. return ERROR_CALL_NOT_IMPLEMENTED;
  1762. }
  1763. DWORD __cdecl svcctl_GetCurrentGroupStateW(void)
  1764. {
  1765. WINE_FIXME("\n");
  1766. return ERROR_CALL_NOT_IMPLEMENTED;
  1767. }
  1768. DWORD __cdecl svcctl_EnumServiceGroupW(
  1769. SC_RPC_HANDLE scmanager,
  1770. DWORD service_type,
  1771. DWORD service_state,
  1772. BYTE *buffer,
  1773. DWORD buf_size,
  1774. DWORD *needed_size,
  1775. DWORD *returned_size,
  1776. DWORD *resume_index,
  1777. LPCWSTR groupname)
  1778. {
  1779. WINE_FIXME("\n");
  1780. return ERROR_CALL_NOT_IMPLEMENTED;
  1781. }
  1782. DWORD __cdecl svcctl_ChangeServiceConfig2A(
  1783. SC_RPC_HANDLE service,
  1784. SC_RPC_CONFIG_INFOA info)
  1785. {
  1786. WINE_FIXME("\n");
  1787. return ERROR_CALL_NOT_IMPLEMENTED;
  1788. }
  1789. DWORD __cdecl svcctl_QueryServiceConfig2A(
  1790. SC_RPC_HANDLE service,
  1791. DWORD info_level,
  1792. BYTE *buffer,
  1793. DWORD buf_size,
  1794. DWORD *needed_size)
  1795. {
  1796. WINE_FIXME("\n");
  1797. return ERROR_CALL_NOT_IMPLEMENTED;
  1798. }
  1799. DWORD RPC_Init(void)
  1800. {
  1801. WCHAR transport[] = SVCCTL_TRANSPORT;
  1802. WCHAR endpoint[] = SVCCTL_ENDPOINT;
  1803. DWORD err;
  1804. if (!(cleanup_group = CreateThreadpoolCleanupGroup()))
  1805. {
  1806. WINE_ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
  1807. return GetLastError();
  1808. }
  1809. if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
  1810. {
  1811. WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
  1812. return err;
  1813. }
  1814. if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
  1815. {
  1816. WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
  1817. return err;
  1818. }
  1819. if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
  1820. {
  1821. WINE_ERR("RpcServerListen failed with error %u\n", err);
  1822. return err;
  1823. }
  1824. exit_event = __wine_make_process_system();
  1825. return ERROR_SUCCESS;
  1826. }
  1827. void RPC_Stop(void)
  1828. {
  1829. RpcMgmtStopServerListening(NULL);
  1830. RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
  1831. RpcMgmtWaitServerListen();
  1832. CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
  1833. CloseThreadpoolCleanupGroup(cleanup_group);
  1834. CloseHandle(exit_event);
  1835. }
  1836. void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
  1837. {
  1838. SC_RPC_HANDLE_destroy(handle);
  1839. }
  1840. void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE handle)
  1841. {
  1842. }
  1843. void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
  1844. {
  1845. return HeapAlloc(GetProcessHeap(), 0, len);
  1846. }
  1847. void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
  1848. {
  1849. HeapFree(GetProcessHeap(), 0, ptr);
  1850. }